[ZOJ3494]BCD Code
2016-02-26 21:09
232 查看
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数组,然后统计答案的时候用正常姿势。。这样好写多了>_<
View Code
大致题意:
BCD码就是把一个数十进制下的每一位分别用4位的二进制表示。
给你一坨01串,问你在一个区间内,有多少个数的BCD码不包含任何一个字符串。
因为涉及到多个串的匹配问题...所以要在AC自动机上DP
f[i][j]表示在自动机上的节点i,再往后走j步 的合法方案数。(合法就是说,经过的路径上不包含任何一个给定字符串)
建完AC自动机后,把非法的节点都删掉,再求出CH[i][j]表示从i节点出发,经过数字j后到达的节点(0<=j<=9),这样好转移= =。
一开始想写递归版本的。。前导0什么的完全无力TAT
后来干脆用记忆化搜索求f数组,然后统计答案的时候用正常姿势。。这样好写多了>_<
#include<cstdio> #include<iostream> #include<cstring> using namespace std; const int modd=1000000009; int fail[2003],ch[2003][2]; int CH[2003][10]; int f[2003][202],u[2003][202];//f[i][j]在自动机上的i节点时,再往后走j步的合法方案数 int i,j,k,n,m,tot,T,ans,len; bool gg[2003]; char s[233];int dl[2333]; inline void insert(int len){ int i,now=0; for(i=0;i<len;i++) s[i]-='0',now=ch[now][s[i]]?ch[now][s[i]]:(ch[now][s[i]]=++tot); gg[now]=1; } inline void build(){ int l=0,r=1,i,now,tmp; while(l<r){ now=dl[++l]; for(i=0;i<=1;i++)if(ch[now][i]){ for(tmp=fail[now];tmp&&!ch[tmp][i];tmp=fail[tmp]); fail[ch[now][i]]=(now==0)?0:ch[tmp][i]; gg[ch[now][i]]|=gg[fail[ch[now][i]]]|gg[now]; dl[++r]=ch[now][i]; }else{ for(tmp=fail[now];tmp&&!ch[tmp][i];tmp=fail[tmp]); ch[now][i]=ch[tmp][i]; } } for(i=0;i<=tot;i++)for(j=0;j<=1;j++)if(gg[ch[i][j]]||gg[i])ch[i][j]=-233; for(i=0;i<=tot;i++)if(!gg[i]) for(j=0;j<=9;j++){ for(now=i,k=8;k&&now!=-233;k>>=1) now=ch[now][(k&j)!=0]; CH[i][j]=now;//printf(" %d->%d %d\n",i,j,CH[i][j]); } for(i=0;i<=tot;i++)if(!gg[i])f[i][0]=1,u[i][0]=T; } inline int dfs(int x,int step){ if(u[x][step]==T)return f[x][step]; int ans=0; for(int i=0;i<=9;i++)if(CH[x][i]!=-233) ans+=dfs(CH[x][i],step-1),ans-=ans>=modd?modd:0; u[x][step]=T,f[x][step]=ans;//printf(" f: %d %d %d\n",x,step,f[x][step]); return ans; } inline int get(int len){//求区间[1,len)内合法方案数 register int i,j,ans=0,now; for(i=0;i<len;i++)s[i]-=48; for(i=1;i<len;i++)for(j=1;j<=9;j++)if(CH[0][j]!=-233) ans+=dfs(CH[0][j],i-1),ans-=ans>=modd?modd:0; for(i=1;i<s[0];i++)if(CH[0][i]!=-233)ans+=dfs(CH[0][i],len-1),ans-=ans>=modd?modd:0; now=CH[0][s[0]]; for(i=1;i<len&&now!=-233;i++){ 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; now=CH[now][s[i]]; } return ans; } inline void add(){ int i,j; for(i=len-1;i>=0;i--)if(s[i]!='9')break; if(i>=0) for(s[i]++,j=i+1;j<len;j++)s[j]='0'; else{ for(s[0]='1',i=1;i<=len;i++)s[i]='0'; len++; } } int main(){ for(scanf("%d",&T);T;T--){ scanf("%d",&n);memset(gg,0,tot+1);memset(ch,0,(tot+1)<<3);tot=0; for(i=1;i<=n;i++) scanf("%s",s),insert(strlen(s)); build(); scanf("%s",s);len=strlen(s);ans=-get(len); scanf("%s",s);len=strlen(s);add();ans+=get(len); if(ans<0)ans+=modd; printf("%d\n",ans); } return 0; }
View Code
相关文章推荐
- Tornado开发技巧
- vector模板的用法
- Abstract(抽象)可以修饰类、方法 http://www.cnblogs.com/suneryong/p/3571362.html
- struts2学习笔记
- OpenGL入门学习(十)
- map的两种取值方式
- css中的BFC
- Hibernate inverse和cascade的作用和区别
- <LeetCode OJ> 96. Unique Binary Search Trees
- mac Zip 常用命令
- C\C++中内存分几个区
- UVALive 3026(KMP)
- Big Event in HDU (HDU_1171) 01背包
- 新手学习opencv七:svm
- MFC 程序隐藏界面
- JavaSE入门学习23:Java面向对象之构造方法
- Zookeeper集群和HBase集群
- LeetCode----Product of Array Except Self
- Python基础回顾之-变量和数据类型
- 数字图像处理-编程实现染色体计数 C语言实现