bzoj 3530 : [Sdoi2014]数数

  一眼AC自动机上DP,f[i][j][0]到第j个节点表示前i位与n一样的方案,1表示不一样的方案。

  事实证明我每回写数位dp都要wa到神志模糊,数据一有0就跪,所以加了各种特判。。。

  因为如果数据中有0032这种的话直接dp会把32判为不合法,而事实上它是合法的,因为要去掉前缀0.

  所以每回从根向0的边转移时要少转移1,相当于把0000....这个全为0的前缀保留在根,为了保留这个前缀还要从第二次开始每次f[i][0][1]++。

  好像每次写数位dp都是加了一堆特判才过的。。。

  

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<queue>
  5 #include<algorithm>
  6 #define p 1000000007
  7 using namespace std;
  8 int m,n;
  9 char s[2000];
 10 int ch[2000][10];int cnt;
 11 bool v[2000];
 12 bool flag;
 13 void build()
 14 {
 15     int len=strlen(s);
 16     int now=0;
 17     for(int i=0;i<len;i++)
 18     {
 19         int c=s[i]-'0';
 20         if(ch[now][c])now=ch[now][c];
 21         else
 22         {
 23             ch[now][c]=++cnt;
 24             now=ch[now][c];
 25         }
 26     }
 27     v[now]=1;
 28 }
 29 queue<int>q;
 30 int f[2000];
 31 int ans;
 32 void AC()
 33 {
 34     for(int i=0;i<10;i++)
 35     {
 36         if(ch[0][i])q.push(ch[0][i]);
 37     }
 38     while(!q.empty())
 39     {
 40         int tmp=q.front();q.pop();
 41         for(int i=0;i<10;i++)
 42         {
 43             if(ch[tmp][i])
 44             {
 45                 f[ch[tmp][i]]=ch[f[tmp]][i];
 46                 q.push(ch[tmp][i]); 
 47                 if(v[f[ch[tmp][i]]])v[ch[tmp][i]]=1;
 48             }
 49             else
 50             {
 51                 ch[tmp][i]=ch[f[tmp]][i];
 52             }
 53         }
 54     }
 55 }
 56 int now[2000][2],pre[2000][2];
 57 char a[2000];
 58 int be[2000];
 59 int main()
 60 {
 61     scanf("%s",a);
 62     n=strlen(a);
 63     scanf("%d",&m);
 64     for(int i=1;i<=m;i++)
 65     {
 66         scanf("%s",s);
 67         build();
 68     }
 69     AC();
 70     pre[0][0]=1;
 71     for(int i=0;i<n;i++)
 72     {
 73         int x=a[i]-'0';
 74         if(i)pre[0][1]++;
 75         for(int j=0;j<=cnt;j++)
 76         {
 77             if(v[j])continue;
 78             for(int k=0;k<x;k++)
 79             {
 80                 if(!i&&!k)continue;
 81                 now[ch[j][k]][1]+=pre[j][0];
 82                 now[ch[j][k]][1]%=p;
 83             }
 84             now[ch[j][x]][0]+=pre[j][0];
 85             now[ch[j][x]][0]%=p;
 86             for(int k=0;k<10;k++)
 87             {
 88                 now[ch[j][k]][1]+=pre[j][1]-(!j&&k==0&&i!=0);
 89                 now[ch[j][k]][1]%=p;
 90             }
 91         }
 92         for(int j=0;j<=cnt;j++)
 93         {
 94             if(v[j])continue;
 95             if(i==n-1)
 96             {
 97                 ans+=now[j][1];
 98                 if(ans>=p)ans-=p;
 99                 ans+=now[j][0];
100                 if(ans>=p)ans-=p;
101             }
102             pre[j][0]=now[j][0];
103             pre[j][1]=now[j][1];
104             now[j][0]=now[j][1]=0;
105         }
106     }
107     printf("%d\n",ans);
108     return 0;
109 }

 

posted @ 2017-02-23 22:47  SD_le  阅读(265)  评论(0编辑  收藏  举报
重置按钮