zoukankan      html  css  js  c++  java
  • [ZOJ3494]BCD Code

      AC自动机+数位DP。

      大致题意:

        BCD码就是把一个数十进制下的每一位分别用4位的二进制表示。

        给你一坨01串,问你在一个区间内,有多少个数的BCD码不包含任何一个字符串。

      因为涉及到多个串的匹配问题...所以要在AC自动机上DP

      f[i][j]表示在自动机上的节点i,再往后走j步 的合法方案数。(合法就是说,经过的路径上不包含任何一个给定字符串)

      建完AC自动机后,把非法的节点都删掉,再求出CH[i][j]表示从i节点出发,经过数字j后到达的节点(0<=j<=9),这样好转移= =。

      一开始想写递归版本的。。前导0什么的完全无力TAT

      后来干脆用记忆化搜索求f数组,然后统计答案的时候用正常姿势。。这样好写多了>_<

      结果交完直接#1了。。我是没看出来自己的写法哪里常数优越= =

      其实这题只比普通模版题多了个AC自动机而已。。。其他甚至还简单点

      就算是递归版的,只要好好想一下前导零的问题就行了吧...网上递归版的标程也不长

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 using namespace std;
     5 const int modd=1000000009;
     6 int fail[2003],ch[2003][2];
     7 int CH[2003][10];
     8 int f[2003][202],u[2003][202];//f[i][j]在自动机上的i节点时,再往后走j步的合法方案数 
     9 int i,j,k,n,m,tot,T,ans,len;
    10 bool gg[2003];
    11 
    12 char s[233];int dl[2333];
    13 
    14 inline void insert(int len){
    15     int i,now=0;
    16     for(i=0;i<len;i++)
    17         s[i]-='0',now=ch[now][s[i]]?ch[now][s[i]]:(ch[now][s[i]]=++tot);
    18     gg[now]=1;
    19 }
    20 inline void build(){
    21     int l=0,r=1,i,now,tmp;
    22     while(l<r){
    23         now=dl[++l];
    24         for(i=0;i<=1;i++)if(ch[now][i]){
    25             for(tmp=fail[now];tmp&&!ch[tmp][i];tmp=fail[tmp]);
    26             fail[ch[now][i]]=(now==0)?0:ch[tmp][i];
    27             
    28             gg[ch[now][i]]|=gg[fail[ch[now][i]]]|gg[now];
    29             dl[++r]=ch[now][i];
    30         }else{
    31             for(tmp=fail[now];tmp&&!ch[tmp][i];tmp=fail[tmp]);
    32             ch[now][i]=ch[tmp][i];
    33         }
    34     }
    35     for(i=0;i<=tot;i++)for(j=0;j<=1;j++)if(gg[ch[i][j]]||gg[i])ch[i][j]=-233;
    36     for(i=0;i<=tot;i++)if(!gg[i])
    37         for(j=0;j<=9;j++){
    38             for(now=i,k=8;k&&now!=-233;k>>=1)
    39                 now=ch[now][(k&j)!=0];
    40             CH[i][j]=now;//printf("   %d->%d %d
    ",i,j,CH[i][j]);
    41         }
    42     for(i=0;i<=tot;i++)if(!gg[i])f[i][0]=1,u[i][0]=T;
    43 }
    44 inline int dfs(int x,int step){
    45     if(u[x][step]==T)return f[x][step];
    46     int ans=0;
    47     for(int i=0;i<=9;i++)if(CH[x][i]!=-233)
    48         ans+=dfs(CH[x][i],step-1),ans-=ans>=modd?modd:0;
    49     u[x][step]=T,f[x][step]=ans;//printf("   f: %d %d  %d
    ",x,step,f[x][step]);
    50     return ans;
    51 }
    52 inline int get(int len){//求区间[1,len)内合法方案数 
    53     register int i,j,ans=0,now;
    54     for(i=0;i<len;i++)s[i]-=48;
    55     for(i=1;i<len;i++)for(j=1;j<=9;j++)if(CH[0][j]!=-233)
    56         ans+=dfs(CH[0][j],i-1),ans-=ans>=modd?modd:0;
    57     for(i=1;i<s[0];i++)if(CH[0][i]!=-233)ans+=dfs(CH[0][i],len-1),ans-=ans>=modd?modd:0;
    58     
    59     now=CH[0][s[0]];
    60     for(i=1;i<len&&now!=-233;i++){
    61         for(j=0;j<s[i];j++)if(CH[now][j]!=-233)ans+=dfs(CH[now][j],len-i-1),ans-=ans>=modd?modd:0;
    62         now=CH[now][s[i]];
    63     }
    64     return ans;
    65 }
    66 inline void add(){
    67     int i,j;
    68     for(i=len-1;i>=0;i--)if(s[i]!='9')break;
    69     if(i>=0)
    70         for(s[i]++,j=i+1;j<len;j++)s[j]='0';
    71     else{
    72         for(s[0]='1',i=1;i<=len;i++)s[i]='0';
    73         len++;
    74     }
    75 }
    76 int main(){
    77     for(scanf("%d",&T);T;T--){
    78         scanf("%d",&n);memset(gg,0,tot+1);memset(ch,0,(tot+1)<<3);tot=0;
    79         for(i=1;i<=n;i++)
    80             scanf("%s",s),insert(strlen(s));
    81         build();
    82         scanf("%s",s);len=strlen(s);ans=-get(len);
    83         scanf("%s",s);len=strlen(s);add();ans+=get(len);
    84         if(ans<0)ans+=modd;
    85         printf("%d
    ",ans);
    86     }
    87     return 0;
    88 }
    View Code
  • 相关阅读:
    java10 var
    java lambda,方法引用
    Java集合总结
    Oracle/Sun JDK与OpenJDK的区别和联系
    IO基本知识
    字符串反转2单词内部不进行转换
    反转String 1
    java 左移<<&>>右移&>>无符号右移
    反射
    equals方法与hashcode方法
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5221802.html
Copyright © 2011-2022 走看看