3530: [Sdoi2014]数数

来源:互联网 发布:平安证券炒股软件 编辑:程序博客网 时间:2024/05/24 07:13

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

2032314

Sample Output

14

HINT
下表中l表示N的长度,L表示S中所有串长度之和。
1 < =l < =1200 , 1 < =M < =100 ,1 < =L < =1500

题解

就先建一个AC自动机
然后做一下数位DP就好了
代码很丑,看看数组的表示就好了

要注意的是,2和02不是一个东西

#include<cstdio>#include<algorithm>#include<iostream>#include<cstring>#include<queue>using namespace std;const int MOD=1e9+7;const int N=1505;struct node{     int son[10],fail;     bool tf;//是不是终点 }s[N];int num=0;char ss[N];int m;void init (int x){    //printf("%d\n",x);    s[x].tf=false;s[x].fail=0;    for (int u=0;u<10;u++) s[x].son[u]=-1;}void bt (){    int len=strlen(ss),now=0;    for (int u=0;u<len;u++)    {        int x=ss[u]-'0';        if (s[now].son[x]==-1)        {            s[now].son[x]=++num;            init(num);        }        now=s[now].son[x];    }    //printf("YES:%d\n",now);    s[now].tf=true;}queue<int> q;void bfs (){    int x;q.push(0);    while (!q.empty())    {        int x=q.front();        for (int u=0;u<10;u++)        {            int son=s[x].son[u],f=s[x].fail;            if (son>=0)            {                if (x==0) s[son].fail=0;                else s[son].fail=s[f].son[u];                q.push(son);            }            else            {                if (x==0) s[x].son[u]=0;                else s[x].son[u]=s[f].son[u];            }        }        q.pop();    }}bool vis[N];void dfs (int x){    if (vis[x]) return ;    vis[x]=true;    int Fail=s[x].fail;    dfs(Fail);    s[x].tf=(s[x].tf|s[Fail].tf);}char n[N];int ooo;int f[N][2][2][N];int solve (int x,bool tf,bool tf1,int y)//当前到第几位了    是否已经小了 是否非0位    在AC自动机上是哪一位{    if (tf1==false) y=0;    if (s[y].tf==true) return 0;//  printf("%d %d %d %d\n",x,tf,tf1,y);    if (x>ooo) return tf1==false?0:1;    if (f[x][tf][tf1][y]!=0) return f[x][tf][tf1][y];    if (tf==true)//可以随便填     {        f[x][tf][tf1][y]=(f[x][tf][tf1][y]+solve(x+1,true,tf1,s[y].son[0]))%MOD;//填0         for (int u=1;u<=9;u++)        {        //  printf("NO:%d %d %d %d\n",x,u,solve(x+1,true,true,s[y].son[u]),s[y].son[u]);            f[x][tf][tf1][y]=(f[x][tf][tf1][y]+solve(x+1,true,true,s[y].son[u]))%MOD;        }    }    else    {        int now=n[x]-'0';        if (0!=now) f[x][tf][tf1][y]=(f[x][tf][tf1][y]+solve(x+1,true,tf1,s[y].son[0]))%MOD;        for (int u=1;u<now;u++)             f[x][tf][tf1][y]=(f[x][tf][tf1][y]+solve(x+1,true,true,s[y].son[u]))%MOD;        if (now==0) f[x][tf][tf1][y]=(f[x][tf][tf1][y]+solve(x+1,false,tf1,s[y].son[now]))%MOD;        else f[x][tf][tf1][y]=(f[x][tf][tf1][y]+solve(x+1,false,true,s[y].son[now]))%MOD;    }//  printf("YES:%d %d %d %d %d\n",x,tf,tf1,y,f[x][tf][tf1][y]);    return f[x][tf][tf1][y]; }int main(){    memset(f,0,sizeof(f));    scanf("%s",n+1); ooo=strlen(n+1);    scanf("%d",&m);    init(0);    for (int u=1;u<=m;u++)    {        scanf("%s",ss);        bt();    }    bfs();    memset(vis,false,sizeof(vis));vis[0]=true;    for (int u=1;u<=num;u++)        {        //if (s[u].tf) printf("OZY:%d\n",u);        dfs(u);    }    printf("%d\n",(solve(1,false,false,0)+MOD)%MOD);    return 0;}
原创粉丝点击