ZOJ 3494 BCD Code AC自动机+数位DP
来源:互联网 发布:淘宝店铺自动回复 编辑:程序博客网 时间:2024/04/30 14:49
【题目大意】
求[l,r]中,满足题意的数字的个数。如果x改为对应的BCD码的字符串,没有病毒子串,就认为合法的。如假设病毒串为“00”,数字“127”(000100100111)就是非法的,数字“7”(0111)是合法的。
【思路】
我刚开始思考,把病毒串改为对应的一个或多个10进制串,发现状态数反而改多了 = =!。认真思考,发现根本没有必要,建立AC自动机后,类似数位DP,用dp[ i ][ j ][ k ]表示从高到低放到第i位了,j表示前i位是否都达到对应数字的最大,在AC自动机的状态为k,的方法数。之后做DP就是了。
我敲好了后,发现样例都过不到o(╯□╰)o,认真找bug后,发现数字的前导0不应该算做字符串...好吧,把第二维稍微改一下,j==0表示前i位全是0,j==2表示前i位都达到了对应数字的最大,其他用j==1表示。然后改好了,submit,WA~~又找bug,原来是求[l,r]中 l-1后也许比数字l的位数更低了,过多的前导0会使得我的程序错误,这个改好了后就能A了
【优化】
只选取有效状态:k的范围不需要是AC自动机的全部节点,只需要其中可能合法的。
预处理AC自动机的转移:因为数字0-9对应的BCD码是4位的,这个其实可以先处理下,做DP的时候直接O(1)转移。
//#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<cmath>#include<cctype>#include<string>#include<algorithm>#include<iostream>#include<ctime>#include<map>#include<set>using namespace std;#define MP(x,y) make_pair((x),(y))#define PB(x) push_back(x)//typedef __int64 LL;//typedef unsigned __int64 ULL;/* ****************** */const int INF = 100011122;const double INFF = 1e100;const double eps = 1e-8;const int mod = 1000000009;const int NN = 210;const int MM = 5000010;/* ****************** */const int k_size = 2;const int SUM_LEN = 2005;struct Tire_tree{ int fail; bool ok; int next[k_size]; void init() { memset(next, -1, sizeof(next)); fail = -1; ok = true; }}tire[SUM_LEN];int tire_q[SUM_LEN];char ss[SUM_LEN];int re[SUM_LEN];//有效状态int dui[SUM_LEN];bool vis[SUM_LEN];int a[205];int dp[2][3][2005];int bian4[SUM_LEN][10],ok4[SUM_LEN][10];void tire_insert(char* ss,int root,Tire_tree* tire,int& tire_cnt){ int i, x, p = root; for(i = 0; ss[i]; i++) { x = ss[i]-'0'; if(tire[p].next[x]==-1) { tire[p].next[x] = ++tire_cnt; tire[tire_cnt].init(); } p = tire[p].next[x]; } tire[p].ok = false;}int init_fail(int root,Tire_tree* tire,int& tire_cnt){ int i, p, fa, head, tail; int tol, zt, j, k, nn[4] = {8, 4, 2, 1}; bool fg; p = root; head = 1; tail = 0; tire[root].fail = root; for(i = 0; i < k_size; i++) { if(tire[p].next[i]!=-1) { tire_q[++tail] = tire[p].next[i]; tire[ tire_q[tail] ].fail = root; } else tire[p].next[i] = root; } while(head<=tail) { p = tire_q[head++]; fa = tire[p].fail; if(!tire[fa].ok) tire[p].ok = false; for(i = 0; i < k_size; i++) { if(tire[p].next[i]!=-1) { tire_q[ ++tail ] = tire[p].next[i]; tire[ tire_q[tail] ].fail = tire[fa].next[i]; } else tire[p].next[i] = tire[fa].next[i]; } } for(i = 0; i <= tire_cnt; i++) vis[i] = false; vis[root] = true; tire_q[head = tail = 0] = root; while(head <= tail) { fa = tire_q[head++]; for(i = 0; i < k_size; i++) { p = tire[fa].next[i]; if(tire[p].ok && !vis[p]) { tire_q[++tail] = p; vis[p] = true; } } } tol = 0; for(i = 0; i <= tire_cnt; i++) { if(vis[i]) { re[++tol] = i; dui[i] = tol; } } for(i = 1; i <= tol; i++) { for(k = 0; k < 10; k++) { fg = true; zt = re[i]; for(j = 0; j < 4; j++) { if(k&nn[j]) zt = tire[zt].next[1]; else zt = tire[zt].next[0]; fg = fg&tire[zt].ok; } zt = dui[zt]; bian4[i][k] = zt; ok4[i][k] = fg; } } return tol;}void INC(int& a,int b){ a += b; if(a >= mod) a -= mod;}int solve(char* ss,int tol,int del){ int i, t, j, k, zt, cnt = 0; bool fg; int j1, j2, en; for(i = 0; ss[i]; i++, cnt++) { a[i+1] = ss[i]-'0'; } a[cnt] -= del; for(i = cnt; i >= 1 ;i--) { if(a[i] < 0) { a[i] += 10; a[i-1] -= 1; } else break; } for(i = 1; i<cnt; i++) { if(a[i]!=0) break; } for(j = 1; i<=cnt; i++,j++) { a[j] = a[i]; } cnt = j-1;// cout<<"cnt=="<<cnt<<endl;// cout<<"shu==";// for(i = 1; i <= cnt; i++)// {// cout<<a[i]<<" ";// }// cout<<endl; memset(dp, 0, sizeof(dp)); dp[0][2][1] = 1; t = 0; for(i = 0; i < cnt; i++) { t = 1-t; for(j = 1; j <= tol; j++) dp[t][0][j] = dp[t][1][j] = dp[t][2][j] = 0; for(j = 1; j <= tol; j++) { for(j1 = 0; j1 < 3; j1++) { if(dp[1-t][j1][j]==0)continue; if(j1==2)en = a[i+1]; else en = 9; for(k = 0; k <= en; k++) { if(k==0 && (j1==0 || i==0)) { fg = true; zt = j; } else { zt = bian4[j][k]; fg = ok4[j][k]; } if(fg) { if(j1==2 && k==en) j2 = 2; else if(k==0 && (i==0 || j1==0)) j2 = 0; else j2 = 1; INC(dp[t][j2][zt],dp[1-t][j1][j]); } } } } } int ans = 0; for(j = 1; j <= tol; j++) { INC(ans, dp[t][0][j]); INC(ans, dp[t][1][j]); INC(ans, dp[t][2][j]); } return ans;}int main(){ int cas; int i, n; int root, tire_cnt; int tol, ans; scanf("%d",&cas); while(cas--) { root = tire_cnt = 0; tire[root].init(); scanf("%d",&n); for(i = 0; i < n; i++) { scanf("%s",ss); tire_insert(ss, root, tire, tire_cnt); }// for(i = 0; i <= tire_cnt; i++)// {// cout<<"check== "<<tire[i].next[0]<<" "<<tire[i].next[1]<<endl;// } tol = init_fail(root, tire, tire_cnt);// cout<<"tol=="<<tol<<endl;// for(i = 0; i <= tire_cnt; i++)// {// cout<<"check== "<<tire[i].next[0]<<" "<<tire[i].next[1]<<endl;// }// for(i = 1; i <= tol; i++)// {// cout<<"re=="<<re[i]<<endl;// }// cout<<dui[0]<<" "<<dui[1]<<endl; scanf("%s",ss); ans = -solve(ss, tol, 1); // cout<<"ans1=="<<-ans<<endl; scanf("%s",ss); // cout<<"ans2=="<<solve(ss,tol,0)<<endl; ans += solve(ss, tol, 0); if(ans < 0)ans += mod; // cout<<"ans=="; printf("%d\n",ans); } return 0;}
0 0
- ZOJ 3494 BCD Code(AC自动机+数位DP)
- ZOJ 3494 BCD Code 数位DP+AC自动机
- ZOJ 3494 BCD Code (AC自动机+数位DP,5级)
- 【MZ】ZOJ 3494 BCD Code AC自动机+数位DP
- ZOJ 3494 BCD Code(AC自动机+数位DP)
- ZOJ 3494 BCD Code(AC自动机+数位DP)
- ZOJ 3494 BCD Code AC自动机+数位DP
- ZOJ 3494 BCD Code AC自动机+数位DP
- 【ZOJ】3494 BCD Code AC自动机+数位DP
- zoj 3494 BCD Code AC自动机+数位dp
- zoj 3494 BCD Code(AC自动机+数位dp)
- ZOJ 3494 BCD Code AC自动机 + 数位DP
- 【AC自动机+数位DP】【zoj 3494】BCD Code
- ZOJ Problem Set - 3494 BCD Code AC自动机+数位DP
- zoj 3494 BCD Code (ac自动机+数位dp)
- [AC自动机+数位dp] zoj 3494 BCD Code
- ZOJ - 3494 BCD Code(AC自动机+数位DP)
- ZOJ 3494 BCD Code (AC自动机 + 数位DP)
- Netflix逆袭:从失足青年到硅谷精英
- java 汉字转换为拼音 简码 及全拼音
- Unix网络编程:while中执行waitpid为什么能正确解决同时出现的多个子进程结束
- Zedboard & Zynq 图像采集 视频开发 (五) 板端Linux下视频TCP发送 & Linux上位机QT视频显示
- 二叉查找树
- ZOJ 3494 BCD Code AC自动机+数位DP
- WCE 电源管理器(开胃菜)
- Monkeyrunner 新手入门
- 百度API地图的标注不是居中显示,而是显示在左上角
- 《鸟哥的Linux私房菜:基础学习篇》(高清第三版)
- 主成分分析(PCA)——以2维图像为例
- Windows Server 2008 R2 实现多用户同时登陆
- 智能家居之智能产品的表现形式
- 处理内存泄漏c++