和Leo一起做爱字符串的好孩子之 [SDOI2014]数数

原文链接: http://www.cnblogs.com/Leo-JAM/p/10079131.html

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

AC自动机+数位DP

怎么解决?

构建Trie图

因为只有在Trie图上才能对答案DP并识别所有的非合法串

DP转移很繁琐

但是还是就那么写

F_{i,j,k}i表示是否顶到上界j为第j位(N)k为第k个节点

特判长度不够的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int mod=1e9+7;
const int N=2e4+100;
char C[N];
char S[N];
struct AC_AuTo{
    struct Node{
        int vis[10];
        int end;
        int fail;
    }AC[N];
    /*int cnt;
    inline void Clear(int p){
        AC[p].end=0;
        AC[p].fail=0;
        memset(AC[p].vis,0,sizeof(AC[p].vis));
    }
    inline void Insert(string S){
        int R=S.length();
        int now=0;
        for(int i=0;i<R;i++){
            if(!AC[now].vis[S[i]-'0']){
                cnt++;
                Clear(cnt);
                AC[now].vis[S[i]-'0']=cnt;
            }
            now=AC[now].vis[S[i]-'0'];
        }
        AC[now].end=1;
    }
    inline void GetFail(){
        queue<int> Q;
        for(int i=0;i<10;i++){
            if(AC[0].vis[i]){
                AC[AC[0].vis[i]].fail=0;
                Q.push(AC[0].vis[i]);
            }
        }
        while(!Q.empty()){
            int x=Q.front();
            Q.pop();
            for(int i=0;i<10;i++){
                if(AC[x].vis[i]){
                    AC[AC[x].vis[i]].fail=AC[AC[x].fail].vis[i];
                    Q.push(AC[x].vis[i]);
                    AC[AC[x].vis[i]].end|=AC[AC[AC[x].vis[i]].fail].end;
                }
                else AC[x].vis[i]=AC[AC[x].fail].vis[i];
            }
        }
    }*/
    int cnt;
    void Clear(int p){
        AC[p].fail=AC[p].end=0;
        memset(AC[p].vis,0,sizeof(AC[p].vis));
    }
    void Insert(char *S){
        int now=0;
        int len=strlen(S);
        for(int i=0;i<len;++i){
            if(!AC[now].vis[S[i]-'0']){
                AC[now].vis[S[i]-'0']=++cnt;
                Clear(cnt);
            }
            now=AC[now].vis[S[i]-'0'];
        }
        AC[now].end=1;
    }
    void GetFail(){
        queue<int> Q;
        for(int i=0;i<10;++i){
            if(AC[0].vis[i]){
                AC[AC[0].vis[i]].fail=0;
                Q.push(AC[0].vis[i]);
            }
        }
        while(!Q.empty()){
            int x=Q.front();
            Q.pop();
            for(int i=0;i<10;++i){
                if(AC[x].vis[i]){
                    AC[AC[x].vis[i]].fail=AC[AC[x].fail].vis[i];
                    AC[AC[x].vis[i]].end|=AC[AC[AC[x].fail].vis[i]].end;
                    Q.push(AC[x].vis[i]);
                }
                else AC[x].vis[i]=AC[AC[x].fail].vis[i];
            }
        }
    }
    int F[2][1300][1600];
    int m;
    void Build(){
        cin>>m;
        for(int i=1;i<=m;++i){
            cin>>S;
            Insert(S);
        }
        GetFail();
    }
    void Solve(){
        cin>>(C+1);
        Build();
        int n=strlen(C+1); 
        for(int i=0;i<n;++i){
            for(int j=0;j<=cnt;++j){
                if(F[0][i][j]){
                    int len=C[i+1]-'0';
                    for(int k=0;k<len;++k){
                        if(!AC[AC[j].vis[k]].end)F[1][i+1][AC[j].vis[k]]=(F[1][i+1][AC[j].vis[k]]+F[0][i][j])%mod;
                    }
                    if(!AC[AC[j].vis[len]].end)F[0][i+1][AC[j].vis[len]]=(F[0][i+1][AC[j].vis[len]]+F[0][i][j])%mod;
                }
                if(F[1][i][j]){
                    for(int k=0;k<=9;++k){
                        if(!AC[AC[j].vis[k]].end)F[1][i+1][AC[j].vis[k]]=(F[1][i+1][AC[j].vis[k]]+F[1][i][j])%mod;
                    }
                }
                if(!j){
                    if(!i){
                        int len=C[i+1]-'0';
                        for(int k=1;k<len;++k){
                            if(!AC[AC[j].vis[k]].end)F[1][i+1][AC[j].vis[k]]+=1;
                        }						
                        if(!AC[AC[j].vis[len]].end)F[0][i+1][AC[j].vis[len]]+=1;
                    }	
                    else{
                        for(int k=1;k<=9;++k){
                            if(!AC[AC[j].vis[k]].end)F[1][i+1][AC[j].vis[k]]+=1;
                        }
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<=cnt;++i){
            ans=(ans+F[0][n][i])%mod;
            ans=(ans+F[1][n][i])%mod;
        }
        cout<<ans;
    }
}Solution;
int main(){
//	freopen("test.in","r",stdin);
    Solution.Solve();
}

转载于:https://www.cnblogs.com/Leo-JAM/p/10079131.html

猜你喜欢

转载自blog.csdn.net/weixin_30266829/article/details/94808600