2011DLUT现场赛 2道铜牌难度题

来源:互联网 发布:淘宝金融服务 编辑:程序博客网 时间:2024/04/27 20:35

 E

TLE的方法:【也是现场赛卡住陆神的方法,状态n^2 决策n 结果悲剧的TLE了,semilive的时候我们也用的这个方法,MLE了。。。】

当时犯了致命的错误,以为优化了转移代价就可以降低复杂度,结果发现决策也是n的。

对于一个含 I 、 D 、 ?的链,遇到?号就断链 ,然后是对于无?的序列, 可以考虑成是某个前一个序列插入一个最大值,这个最大值只能出现最在极大值,和边界上。。

#include <cstdio>#include <string>#include <cstring>#include <iostream>typedef long long ll;using namespace std;const int maxn=1020;const ll mod=1000000007ll;char str[maxn];ll com[maxn][maxn];ll DP[maxn*maxn];int n;int qmark[maxn];//以i为起点向后遇到的第一个问号的位置int IDmark[maxn];//以i为起点向后遇到的第一个ID序列的I的位置void init(){    com[0][0]=1;    com[1][0]=1;    com[1][1]=1;    for (int i=2 ; i<maxn-1 ; ++i)    {        com[i][0]=1;        for (int j=1 ; j<=i; ++j)            com[i][j]=(com[i-1][j]+com[i-1][j-1])%mod;            //,printf(" i j %d %d %d\n" , i , j , com[i][j]);    }}ll dp(int sta){    if(sta<0)return 1ll;    ll ans = 0;    int x=sta%n , y=sta/n;    if(y>=n)return 1ll;    if(x>y)return 1ll;    int len=y-x+1;    //printf("sta=%d  x=%d y=%d len=%d\n" ,sta, x , y , len);    if(DP[sta])return DP[sta];    if(len==1 && str[x]!='?')return DP[sta]=1ll;    if(len==1 && str[x]=='?')return DP[sta]=2ll;    /*    for (int i=0 ; i<len ; ++i)    {        if(str[i]=='?')        {            //printf("%I64d\n",dp(ss.substr(0,i)));           ans += (dp(0,i)*dp(ss.substr(i+1,len))%mod*com[len+1][i+1]%mod);           return DP[strmap[ss]]=(ans == 0? 1:ans);        }    }    */    int &j=qmark[x];    if(~j && j<=y)    {        //printf(" %d  %d ??? %d %d\n",x,y,j,j-x+1);        ans=(dp((j-1)*n+x)*dp(y*n+j+1)%mod*com[len+1][j-x+1]%mod);        return DP[sta]=ans;    }    int p=IDmark[x];    while ((~p) && p<y)    {        //printf("p===%d\n",p);        //printf("%d==\n",(p-1)*n+x);        //printf("%d  %d==\n",len,p-x+1);        //printf("com==%lld\n",com[len][p-x+1]);        ans=(ans+(dp((p-1)*n+x)*dp(y*n+p+2)%mod*com[len][p-x+1]%mod))%mod;        p=IDmark[p+1];    }    if(str[x]=='D')ans=(ans+dp(y*n+x+1))%mod;    if(str[y]=='I')ans=(ans+dp((y-1)*n+x))%mod;    return DP[sta]=(ans==0?1:ans)%mod;    /*    for (int i=0 ; i<len-1 ; ++i)    {        if(ss[i]=='I' && ss[i+1]=='D')        {            ans += (dp(ss.substr(0,i))*dp(ss.substr(i+2,len))%mod*com[len][i+1]%mod);        }    }    if(ss[len-1]=='I')ans+=dp(ss.substr(0,len-1));    return DP[strmap[ss]]=(ans == 0? 1:ans);    */}int main(){    init();    while (~scanf("%s",str))    {        memset (DP , 0 , sizeof(DP));        memset (qmark , -1 , sizeof(qmark));        memset (IDmark , -1 , sizeof(IDmark));        n=strlen(str);        for (int i=0 ; i<n ; ++i)        {            if(str[i]=='?')            {                int q=i;                while (qmark[q]==-1 && q>=0)                {                    qmark[q]=i;                    q--;                }            }            if(i<n-1)            {                if(str[i]=='I' && str[i+1]=='D')                {                    int q=i;                    while (IDmark[q]==-1 && q>=0)                    {                        IDmark[q]=i;                        q--;                    }                }            }        }        //for (int i=0 ; i<n ; ++i)        //printf("qmark==%d   IDmark==%d\n", qmark[i], IDmark[i]);        printf("%lld\n",dp((n-1)*n+0)%mod);//rear * n+head ;    }    return 0;}


 

AC的方法:状态n^2 , 时间o(n^2) ,空间o(n)。

DP[i][j]表示剩余i个数 , 有j个数比当前数小

#include <cstdio>#include <cstring>const int maxn=1005;const int mod=1000000007;char str[maxn];int dp[2][maxn];//剩下有j个比i位上的int sum[2][maxn];int main (){    while (~scanf("%s",str))    {        int n=strlen(str);        for (int i=0 ; i<=n ; ++i)dp[0][i]=1,sum[0][i]=i+1;        int turn=1;        for (int i=n-1 ; i>=0 ; --i , turn^=1)        {            memset (dp[turn] , 0 , sizeof(dp[turn]));            for (int j=0 ; j<=i ; ++j)            {                if(str[n-i-1]!='D')                {                    //for (int k=j+1 ; k<=i+1 ; ++k)                        //dp[i][j]+=dp[i+1][k];                    dp[turn][j]=(dp[turn][j]+sum[turn^1][i+1]-sum[turn^1][j]+mod)%mod;                }                if(str[n-1-i]!='I')                {                    //for (int k=0 ; k<=j ; ++k)                        //dp[i][j]+=dp[i+1][k];                    dp[turn][j]=(dp[turn][j]+sum[turn^1][j])%mod;                }                sum[turn][j]=(j>0?sum[turn][j-1]+dp[turn][j]:dp[turn][j])%mod;            }        }        /*        for (int i=0 ; i<=n+1 ; ++i)        {            for (int j=0 ; j<=n+1 ; ++j)                printf("sum[%d][%d]==%lld  " , i , j , sum[i][j]);            printf("\n");            for (int j=0 ; j<=n+1 ; ++j)                printf("dp[%d][%d]==%lld  ", i , j ,dp[i][j]);            printf("\n");        }        */        printf("%d\n",dp[turn^1][0]%mod);    }    return 0;}


 

I题, 老朱用JAVA大数1Y了,我又用C的逆元敲了下

C代码:

#include <cstdio>#include <cstring>#include <cmath>typedef long long typen;typen mod=1000000007ll;///typen x , y;typen eGCD(typen a , typen b ){    if(!b)    {        x=1 , y=0;        return a;    }    int d=eGCD(b , a%b);    int t=x;    x=y;    y=t-a/b*y;    return d;}///const int maxP=10005;int prime[maxP+1];void getprime(){    memset (prime , 0 , sizeof(prime));    for (int i=2 ; i<=maxP ; ++i)    {        if (!prime[i])prime[++prime[0]]=i;        for (int j=1 ; j<=prime[0] && prime[j]*i<=maxP ; ++j)        {            prime[prime[j]*i]=1;            if(i%prime[j]==0)break;        }    }}int factor[100][2];int faccnt;void getFactors(int x){    faccnt=0;    int  tmp=x;    for (int i=1 ; prime[i]*prime[i]<=tmp ; ++i)    {        factor[faccnt][1]=0;        if(tmp%prime[i]==0)        {            factor[faccnt][0]=prime[i];            while (tmp%prime[i]==0)                factor[faccnt][1]++,tmp/=prime[i];            ++faccnt;        }    }    if(tmp != 1)        factor[faccnt][0]=tmp , factor[faccnt++][1]=1;}///int depth;typen inverse2 , inverse3 , inverse5 ;typen get_n4(typen x){    x=(x*x)%mod;    return (typen)(x*x)%mod;}typen get_sigma_n4(typen n){    return ( inverse5*get_n4(n+1)%mod*(n+1)%mod            -inverse5-inverse5*n%mod+mod+mod+mod            -inverse2*(n*n%mod*(n+1)%mod*(n+1)%mod)%mod            -inverse2*n%mod*(n+1)%mod+mod+mod+mod+mod            -inverse3*n%mod*(n+1)%mod*(n<<1|1)%mod)%mod;}int n;typen ans;void dfs(int p , int cnt , int mul)//Exclusion Principle{    if(p==depth)    {        if(cnt&1)ans=(ans-get_n4(mul)*get_sigma_n4(n/mul)%mod+mod)%mod;        else ans=(ans+get_n4(mul)*get_sigma_n4(n/mul)%mod+mod)%mod;    }    /*    printf("%d  %d \n" , depth , cnt);    printf("~!~! n4===%lld  sigma==%lld %d\n" , get_n4(mul) , get_sigma_n4(n/mul) , n/mul);    printf("ans==%lld  mul==%d p==%d", ans , mul , p);    printf("  f[%d]=%d" , p,factor[p][0]);    printf("dfs(%d %d %d)\n",p , cnt ,mul );    */    else    {        dfs(p+1 , cnt+1 , mul*factor[p][0]);        dfs(p+1 , cnt , mul);    }}int main (){    int cas;    scanf("%d",&cas);    getprime();    eGCD(2 , mod);    inverse2=(x+mod)%mod;    eGCD(3 , mod);    inverse3=x;    eGCD(5 , mod);    inverse5=(x+mod)%mod;    while (cas--)    {        scanf("%d",&n);        getFactors(n);        depth=faccnt;        //printf("%lld\n",get_sigma_n4(n));        //printf("%lld\n",get_n4(n));        ans=0;        dfs(0 , 0 , 1);        printf("%d\n",ans%mod);    }    return 0;}


JAVA代码,以后学了JAVA 这个拿来当模板了:

import java.util.Scanner;import java.math.BigInteger;public class Main {    /**     * @param args the command line arguments     */    static int prime[] = new int[10010];    static int getPrime()    {    for(int i = 0; i < 10010; ++ i) prime[i] = 0;    for (int i = 2; i <= 10000; i++)    {            if (prime[i] == 0) prime[++prime[0]] = i;            for (int j = 1; j <= prime[0] && prime[j]*i<= 10000; j++)            {                prime[prime[j]*i] = 1;                if (i % prime[j] == 0) break;            }        }        return prime[0];    }static int factor[][] = new int[100][3];static int facCnt;static int getFactors(int x){    facCnt = 0;    int tmp = x;    for(int i = 1; prime[i] <= tmp / prime[i]; i++)    {        factor[facCnt][1] = 1;        factor[facCnt][2] = 0;        if(tmp % prime[i] == 0)            factor[facCnt][0] = prime[i];        while(tmp % prime[i] == 0)        {            factor[facCnt][2]++;            factor[facCnt][1] *= prime[i];            tmp /= prime[i];        }        if(factor[facCnt][1] > 1) facCnt++;    }    if(tmp != 1)    {        factor[facCnt][0] = tmp;        factor[facCnt][1] = tmp;        factor[facCnt++][2] = 1;    }    return facCnt;}static BigInteger sumpower(int n){    BigInteger ret = BigInteger.valueOf(n);    ret = (ret.multiply(ret.add(BigInteger.ONE)).            multiply(ret.multiply(BigInteger.valueOf(2)).add(BigInteger.ONE)).            multiply(BigInteger.valueOf(3).multiply(ret.multiply(ret)).add(BigInteger.valueOf(3).multiply(ret)).subtract(BigInteger.ONE))).            divide(BigInteger.valueOf(30));    return ret.mod(modulo);}static BigInteger ans;static BigInteger modulo =  new BigInteger("1000000007");static void dfs(int idx, int fact,int cnt, int n){    if(idx == facCnt)    {        if(cnt % 2 == 1) ans = ans.subtract(BigInteger.valueOf(fact).pow(4).multiply(sumpower(n/fact))).add(modulo).mod(modulo);        else ans = ans.add(BigInteger.valueOf(fact).pow(4).multiply(sumpower(n/fact))).mod(modulo);    }    else    {        dfs(idx+1, fact * factor[idx][0], cnt + 1, n);        dfs(idx+1, fact , cnt, n);    }}    public static void main(String[] args) {        Scanner scan = new Scanner(System.in);        int t, n;        getPrime();        t = scan.nextInt();        while(t-- > 0)        {            n = scan.nextInt();            getFactors(n);            ans = BigInteger.ONE;            dfs(0,1,0,n);            System.out.println(ans.subtract(BigInteger.ONE).add(modulo).mod(modulo));        }    }}


 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 q币不小心充多了怎么办 u盘装系统就一个图标怎么办 淘宝买了东西退货客服不理人怎么办 微信10w限额满了怎么办 微信身份证实名认证超出限额怎么办 微信信用卡消费超过当日限额怎么办 淘宝客服同意退货卖家拒绝怎么办 微信钱包充值话费不到帐怎么办 京东买的显示器过保坏了怎么办 支付宝充话费充错号码是空号怎么办 京东充话费充错了号码该怎么办 微信红包充话费不到账怎么办 支付宝充话费等待第三方发货怎么办 微信充话费显示成功但没收到怎么办 微信退款一直在退款中怎么办 文件大于100发不了微信怎么办 微信的传送文件大于100怎么办 微信钱包话费充值错误怎么办 微信转账到不了账也退不回是怎么办 求人办事微信发红包对方不收怎么办 微信上交了订金对方不退怎么办 交通事故对方伤员堵大门搂腿怎么办 电脑开机桌面文件都没了怎么办 qq飞车手游队长换了微信群怎么办 qq飞车手游登录授权失败怎么办 安装时提示安装包发现错误怎么办 苹果6p升级系统验证失败怎么办 w10开不了机无限重启怎么办 微信朋友圈里的表情图打不开怎么办 金立手机微信启动录音被拒绝怎么办 微信帐号解封后漂流瓶不能用怎么办 微信怎么在电脑上登不上去怎么办 玩旧版60级魔兽经常花屏怎么办? 我的世界手机版物品栏不见了怎么办 苹果手机掉进水里出现花屏该怎么办 球球大作战还没进去停止运行怎么办 ps3 e3硬破芯片坏了怎么办 电话打开后页面上没有东西怎么办 WPS在电脑安装后卸载不了怎么办 ps总要以管理员的身份打开怎么办 3d关的慢保存慢怎么办