zoukankan      html  css  js  c++  java
  • bzoj 3530: [Sdoi2014]数数

    Description

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

    解题报告

    简单题,但有点坑,首先如果没有限制就是一个数位DP板子,对于包含的限制,一般是加一维在AC自动机上的节点号,这样就可以保证不存在包含关系了.
    设状态 (f[i][j][k][l]) 表示前i位数字,目前在AC自动机上的j号节点,选的数字为k,是否严格小于(0/1),其实我是个傻逼,写完以后猛地发现 (k) 这一维是多余的,而且还需要滚动,但还是讲一下我的做法吧,如果严格小于就可以任意选,前缀都相等,就只能选小于 (N) 的这一位的数字,如果走出了包含关系,就不转移.
    最坑的地方来了:

    10
    1
    03
    

    这一组数据,如果不判前导0,那么输出(9), (3) 就被完美的忽略了,所以把 (k) 这一位加一个状态,表示前导0然后特殊转移即可

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    const int N=20005,mod=1e9+7;
    int f[2][N][11][2],fail[N],s[N],n,m;char S[N];
    struct node{
       int nxt[11],mark;
    }a[N];
    void upd(int &x,int y){x+=y;if(x>=mod)x-=mod;}
    int root=0,cnt=0;
    void add(){
       scanf("%s",S);
       int len=strlen(S),p=0;
       for(int i=0;i<len;i++){
          if(a[p].nxt[S[i]-'0'])p=a[p].nxt[S[i]-'0'];
          else a[p].nxt[S[i]-'0']=++cnt,p=cnt;
       }
       a[p].mark=1;
    }
    queue<int>q;
    void getfail(){
       q.push(root);
       int x,u,v;
       while(!q.empty()){
          x=q.front();q.pop();
          for(int i=0;i<10;i++){
             if(!a[x].nxt[i]){
                a[x].nxt[i]=a[fail[x]].nxt[i];
                continue;
             }
             u=fail[x];
             while(u && !a[u].nxt[i])u=fail[u];
             if(a[u].nxt[i] && a[u].nxt[i]!=a[x].nxt[i])
                fail[a[x].nxt[i]]=a[u].nxt[i];
             v=a[x].nxt[i];a[v].mark|=a[fail[v]].mark;q.push(v);
          }
       }
    }
    void work()
    {
       scanf("%s%d",S+1,&m);n=strlen(S+1);
       for(int i=1;i<=n;i++)s[i]=S[i]-'0';
       for(int i=1;i<=m;i++)add();
       getfail();
       int x,to,b;bool t=0,tt=1;
       for(int i=1;i<=s[1];i++){
          x=a[root].nxt[i];
          if(a[x].mark)continue;
          f[t][x][i][i<s[1]]=1;
       }
       f[t][0][10][1]=1;
       for(int i=1;i<n;i++){
          for(int j=0;j<=cnt;j++){
             for(int k=0;k<=9;k++){
                x=f[t][j][k][0];f[t][j][k][0]=0;
                if(x){
                   for(int l=0;l<=s[i+1];l++){
                      to=a[j].nxt[l];if(a[to].mark)continue;
                      b=(l<s[i+1]);
                      upd(f[tt][to][l][b],x);
                   }
                }
                x=f[t][j][k][1];f[t][j][k][1]=0;
                if(x){
                   for(int l=0;l<10;l++){
                      to=a[j].nxt[l];if(a[to].mark)continue;
                      upd(f[tt][to][l][1],x);
                   }
                }
             }
             x=f[t][j][10][1];f[t][j][10][1]=0;
             for(int l=1;l<=10;l++){
                to=a[j].nxt[l];if(a[to].mark)continue;
                upd(f[tt][to][l][1],x);
             }
          }
          t^=1;tt^=1;
       }
       int ans=0;
       for(int i=0;i<=cnt;i++)
          for(int k=0;k<=10;k++)
             for(int l=0;l<=1;l++)
                upd(ans,f[t][i][k][l]);
       ans=(ans-1+mod)%mod;
       printf("%d
    ",ans);
    }
    int main(){work();return 0;}
    
    
  • 相关阅读:
    主流浏览器默认限制的非安全端口号有哪些
    coco2dx实现翻拍效果
    iOS和android游戏纹理优化和内存优化(cocos2d-x)(转载)
    cocos2d-x如何解决图片显示模糊问题
    cocos2dx混合模式应用———制作新手引导高亮区域
    visual studio的项目属性表
    如何提高cocos2d-x-spine骨骼动画加载速度
    如何调试lua脚本
    把.pvr.ccz文件转换成png
    coco2dx加载网络图片并保存
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7638668.html
Copyright © 2011-2022 走看看