[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\n",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\n",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\n",ans); 86 } 87 return 0; 88 }