zoukankan      html  css  js  c++  java
  • bzoj4980: 第一题

    Description

    神犇xzyo听说sl很弱,于是出了一题来虐一虐sl。一个长度为2n(可能有前缀0)的非负整数x是good的,当且仅当
    存在两个长度为n(可能有前缀0)的非负整数a、b满足a+b==10n,并且对于0~9每个数位d,都有Sd(x)==Sd(a)+Sd(
    b)(Sd(x)为x的十进制中d出现了多少次)。例如0829是good的,98+02==100。给出一个长度为2n的序列,其中有些
    位置是问号。将每个问号替换为0~9任意一个数位后,有多少个good数,答案对1000000007取膜。为了sl不被虐死
    ,快告诉他怎么写吧。
    两个数相加为10^n,意味着可以将数位一部分按09,18,27,36,45配对表示较高位的情况,低位有一对19,28,37,46,55产生了一次进位,更低位可以全0。枚举哪一对数产生进位,可以算出0的出现次数-9的出现次数,1-8,2-7,3-6,4-5的值,然后做一次背包。需要特判一些情况:因为两个0可以配对,0-9的值表示的是0至少比9多几个,实际可以再把一些9换成0,但如果19产生进位,必须留下至少一个9(可能来自已确定的数位,也可能必须由?提供)而不能全部换成0。
    #include<bits/stdc++.h>
    typedef long long i64;
    const int P=1e9+7;
    char s[100007];
    int n,t[11],m=0,ts[11];
    i64 f[1007],g[1007],fac[1007],fiv[1007],ans=0;
    i64 _ks[2077][1007],(*ks)[1007]=_ks+1027;
    bool d9=0;
    void cal(int tp){
        memset(f,0,sizeof(f));
        f[0]=1;
        for(int i=0;i<5;++i){
            memset(g,0,sizeof(g));
            if(ts[i]>m||i&&ts[i]<-m)return;
            if(!i){
                while(ts[i]<-m)ts[i]+=2;
                for(int s=0,d=0;s<=m;++s){
                    i64 iv=ks[ts[i]][s];
                    if(!iv)continue;
                    if(tp==1&&!d9&&(s+ts[i])%2==0)iv=(iv-fiv[s]+P)%P;
                    for(int j=s;j<=m;++j)g[j]+=f[j-s]*iv;
                    if(++d>6){
                        d=0;
                        for(int j=0;j<=m;++j)g[j]%=P;
                    }
                }
            }else for(int a=ts[i],b=0,d=0;a+b<=m;++a,++b)if(a>=0){
                int s=a+b;
                i64 iv=fiv[a]*fiv[b]%P;
                for(int j=s;j<=m;++j)g[j]+=f[j-s]*iv;
                if(++d>6){
                    d=0;
                    for(int j=0;j<=m;++j)g[j]%=P;
                }
            }
            for(int j=0;j<=m;++j)f[j]=g[j]%P;
        }
        ans=(ans+f[m]*fac[m])%P;
    }
    i64 pw(i64 a,int n){
        i64 v=1;
        for(;n;n>>=1,a=a*a%P)if(n&1)v=v*a%P;
        return v;
    }
    int main(){
        for(int i=fac[0]=1;i<=1000;++i)fac[i]=i*fac[i-1]%P;
        fiv[1000]=pw(fac[1000],P-2);
        for(int i=1000;i;--i)fiv[i-1]=i*fiv[i]%P;
        scanf("%s",s);
        n=strlen(s);
        if(n&1)return puts("0"),0;
        for(int i=0;i<n;++i){
            if(s[i]=='?')++m;
            else ++t[s[i]-'0'];
            d9|=s[i]=='9';
        }
        for(int i=m;i>=-m;--i){
            for(int a=i,b=0;a+b<=m;++a,++b)if(a>=0)ks[i][a+b]=fiv[a]*fiv[b]%P;
            for(int j=0;j<=m;++j)ks[i][j]=(ks[i][j]+ks[i+2][j])%P;
        }
        for(int i=1;i<=5;++i){
            for(int j=0;j<10;++j)ts[j]=t[j];
            --ts[i],--ts[10-i];
            for(int j=0;j<5;++j)ts[j]=ts[9-j]-ts[j];
            i64 a0=ans;
            cal(i);
            a0=ans-a0;
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    Struts2SpringHibernate整合示例,一个HelloWorld版的在线书店(项目源码+详尽注释+单元测试)
    Java实现蓝桥杯勇者斗恶龙
    Java实现 LeetCode 226 翻转二叉树
    Java实现 LeetCode 226 翻转二叉树
    Java实现 LeetCode 226 翻转二叉树
    Java实现 LeetCode 225 用队列实现栈
    Java实现 LeetCode 225 用队列实现栈
    Java实现 LeetCode 225 用队列实现栈
    Java实现 LeetCode 224 基本计算器
    Java实现 LeetCode 224 基本计算器
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7394939.html
Copyright © 2011-2022 走看看