zoukankan      html  css  js  c++  java
  • 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
    ",(ans+mod)%mod);
    105     return 0;
    106 }
  • 相关阅读:
    ASP.NET编程中非常有用的例子
    打包样式资源
    9.使用类的2个注意点
    面向对象案例
    super必须放到子类this之前
    PHP:根据二维数组中的某个字段进行排序
    Vuex的五个核心属性
    利用按钮控制listview的当前选择项,滚动条跟随动
    c#通过进程名字获取进程路径
    判断客户端是否安装realplayer
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/10035296.html
Copyright © 2011-2022 走看看