BZOJ3530: [Sdoi2014]数数(Trie图,数位Dp)

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

解题思路:

很明显是个数位Dp,相当于n位的不要62,由于不要62的字符个数是可以枚举的,这个不可以。

设计一个状态dp[i][j][onlim(0/1)][zero(0/1)]来表示字符到了 i 位,Trie图上到了 j 号节点,是否压了上线,是否有前导零。

转移则是寻找Trie图上一个子节点,如果不代表字符的结束,那么进一位,判断是否压上界,是否为零即可。

注意子节点为root时不向下转移Trie图(即失配)

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 typedef long long lnt;
  5 const lnt mod=(lnt)(1e9+7);
  6 struct trnt{
  7     int ch[10];
  8     int fl;
  9     bool fin;
 10 }tr[10000];
 11 class queue{
 12     public:
 13         queue(void){h=1,t=0;return ;}
 14         int nxt(int x){if(x+1==100000)return 1;return x+1;}
 15         int front(void){return line[h];}
 16         void pop(void){h=nxt(h);return ;}
 17         void push(int x){t=nxt(t);line[t]=x;return ;}
 18         bool empty(void){return nxt(t)==h;}
 19     private:
 20         int h,t,line[100000];
 21 }Q;
 22 int siz;
 23 int n,m;
 24 int l;
 25 char tmp[1000000];
 26 int num[1201];
 27 lnt dp[1201][1501][2][2];
 28 void Insert(char *a)
 29 {
 30     int root=0;
 31     int len=strlen(a+1);
 32     for(int i=1;i<=len;i++)
 33     {
 34         int c=a[i]-'0';
 35         if(!tr[root].ch[c])
 36             tr[root].ch[c]=++siz;
 37         root=tr[root].ch[c];
 38     }
 39     tr[root].fin=true;
 40     return ;
 41 }
 42 void Build(void)
 43 {
 44     int root=0;
 45     for(int i=0;i<10;i++)
 46         if(tr[root].ch[i])
 47             Q.push(tr[root].ch[i]);
 48     while(!Q.empty())
 49     {
 50         root=Q.front();
 51         Q.pop();
 52         tr[root].fin|=tr[tr[root].fl].fin;
 53         for(int i=0;i<10;i++)
 54             if(tr[root].ch[i])
 55             {
 56                 tr[tr[root].ch[i]].fl=tr[tr[root].fl].ch[i];
 57                 Q.push(tr[root].ch[i]);
 58             }else
 59                 tr[root].ch[i]=tr[tr[root].fl].ch[i];
 60     }
 61     return ;
 62 }
 63 int main()
 64 {
 65     scanf("%s",tmp+1);
 66     l=strlen(tmp+1);
 67     for(int i=1;i<=l;i++)
 68         num[i]=tmp[i]-'0';
 69     scanf("%d",&m);
 70     for(int i=1;i<=m;i++)
 71     {
 72         scanf("%s",tmp+1);
 73         Insert(tmp);
 74     }
 75     Build();
 76     dp[0][0][1][1]=1;
 77     for(int i=1;i<=l;i++)
 78     {
 79         for(int j=0;j<=siz;j++)
 80         {
 81             for(int onlim=0;onlim<2;onlim++)
 82             {
 83                 for(int zero=0;zero<2;zero++)
 84                 {
 85                     if(!dp[i-1][j][onlim][zero])
 86                         continue;
 87                     int lim=onlim*num[i]+(1-onlim)*9;
 88                     for(int c=0;c<=lim;c++)
 89                     {
 90                         if(tr[tr[j].ch[c]].fin)
 91                             continue; 
 92                         int nwlim=onlim&&(c==lim);
 93                         int nwzro=zero&&(!c);
 94                         int nwplc=(1-nwzro)*tr[j].ch[c];
 95                         dp[i][nwplc][nwlim][nwzro]=(dp[i][nwplc][nwlim][nwzro]+dp[i-1][j][onlim][zero])%mod;
 96                     }
 97                 }
 98             }
 99         }
100     }
101     lnt ans=0;
102     for(int i=0;i<=siz;i++)
103         ans=(ans+dp[l][i][1][0]+dp[l][i][0][0])%mod;
104     printf("%lld\n",(ans+mod)%mod);
105     return 0;
106 }

 

posted @ 2018-11-28 22:03  Unstoppable728  阅读(191)  评论(0编辑  收藏  举报