zoukankan      html  css  js  c++  java
  • [Sdoi2014]数数[数位dp+AC自动机]

    3530: [Sdoi2014]数数

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 834  Solved: 434
    [Submit][Status][Discuss]

    Description

    我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。
        给定N和S,计算不大于N的幸运数个数。

    Input


        输入的第一行包含整数N。
        接下来一行一个整数M,表示S中元素的数量。
        接下来M行,每行一个数字串,表示S中的一个元素。

    Output

        输出一行一个整数,表示答案模109+7的值。

    Sample Input

    20
    3
    2
    3
    14

    Sample Output

    14

    HINT

     下表中l表示N的长度,L表示S中所有串长度之和。


    1 < =l < =1200 , 1 < =M < =100 ,1 < =L < =1500

    Source

    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=1505;
    const int mod=1e9+7;
    int n,m,len,cnt=1,b[N],c[N],w[N],fail[N],tr[N][10],q[N];
    char a[N];
    int f[N][N][3];ll ans;
    inline void insert(int *s){
        int now=1;
        for(int i=1;i<=len;i++){
            if(!tr[now][s[i]]) tr[now][s[i]]=++cnt;
            now=tr[now][s[i]];
        }
        w[now]++;
    }
    inline void AC_mach(){
        for(int i=0;i<=9;i++) tr[0][i]=1;
        int p,h=0,t=1;q[t]=1;fail[1]=0;
        while(h!=t){
            int now=q[++h];
            for(int i=0;i<=9;i++){
                if(tr[now][i]){
                    for(p=fail[now];!tr[p][i];p=fail[p]);
                    fail[tr[now][i]]=tr[p][i];
                    q[++t]=tr[now][i];
                }
            }
        }
    }
    inline void dp(int T){
        for(int i=1,p;i<=cnt;i++){
            for(int l=0;l<=1;l++){
                if(w[i]||!f[T-1][i][l]) continue;
                for(int j=0;j<=9;j++){
                    for(p=i;!tr[p][j];p=fail[p]);
                    f[T][tr[p][j]][l+j>b[T]]=(f[T][tr[p][j]][l+j>b[T]]+f[T-1][i][l])%mod;
                    if(!j) f[T][tr[p][j]][2]=(f[T][tr[p][j]][2]+f[T-1][i][l])%mod;//前导0 
                }
            }
        }
    }
    int main(){
        freopen("count.in","r",stdin);
        freopen("count.out","w",stdout);
        scanf("%s",a+1);n=strlen(a+1);
        for(int i=1;i<=n;i++) b[n-i+1]=a[i]-'0';
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%s",a+1);len=strlen(a+1);
            for(int j=1;j<=len;j++) c[len-j+1]=a[j]-'0';
            insert(c);
        }
        AC_mach();
        f[0][1][0]=1;
        for(int i=1;i<=n;i++) dp(i);
        for(int i=1;i<n;i++){
            for(int j=1;j<=cnt;j++){
                if(!w[j]){
                    ans=(ans+(ll)f[i][j][0]+f[i][j][1]-f[i][j][2])%mod;
                }
            }
        }
        for(int i=1;i<=cnt;i++){
            if(!w[i]){
                ans=(ans+(ll)f[n][i][0]-f[n][i][2])%mod;
            }
        }
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    python 基础2.5 循环中continue与breake用法
    python 基础 2.4 while 循环
    python 基础 2.3 for 循环
    python 基础 2.2 if流程控制(二)
    python 基础 2.1 if 流程控制(一)
    python 基础 1.6 python 帮助信息及数据类型间相互转换
    python 基础 1.5 python数据类型(四)--字典常用方法示例
    Tornado Web 框架
    LinkCode 第k个排列
    LeetCode 46. Permutations
  • 原文地址:https://www.cnblogs.com/shenben/p/6417383.html
Copyright © 2011-2022 走看看