【MZ】ZOJ 3494 BCD Code AC自动机+数位DP
2013-10-17 02:03
246 查看
problem:
给你 n 个由 01 串组成的病毒。(0<=n<=100)
一个数的 BCD 编码为每个数字变成四位的二进制(如127 would be:0001 0010 0111)。
问从x到y有多少个数其BCD编码中没有病毒。(0<x<=y<10^(200))
think:
用 AC 自动机得到每个状态,每个状态是否已经构成一个病毒,每个状态后面加一个数字后转移到哪个状态。有了这些处理,就是个简单的数位 DP 了。
CODE:
const int kind = 2; const LL mod = 1000000009; LL f[222][2222];//用于数位DP int bit[222]; char ch[55], str[222]; int fail[2222];//每个状态的fail指针 int child[2222][2];//01两种 int end[2222];//每个状态是否已经包含一整个病毒 int dp[2222][12];//i状态后面加数字j变成dp[i][j]状态 int cnt;//用于记录状态 int newNode(){ ++cnt; child[cnt][0] = child[cnt][1] = -1; end[cnt] = 0; return cnt; } void insert(char *str, int root){ int p = root; for(int i=0; str[i]; ++i){ int k = str[i] - '0'; if(child[p][k] == -1) child[p][k] = newNode(); p = child[p][k]; } end[p] = 1; } //这个建立fail指针不同于hdu2222 //这里的fail不能有空指针,必须要指向一个状态 queue<int>q; void build_fail(int root){ while(!q.empty()) q.pop(); fail[root] = root; q.push(root); while(!q.empty()){ int tmp = q.front(); q.pop(); if(end[fail[tmp]]==1) end[tmp] = 1;//tmp也已经包括病毒 for(int k = 0; k < kind; ++k){ if(child[tmp][k]!=-1){ if(tmp==root) fail[child[tmp][k]] = root; else fail[child[tmp][k]] = child[fail[tmp]][k]; q.push(child[tmp][k]); } else { if(tmp==root) child[root][k] = root; else child[tmp][k] = child[fail[tmp]][k]; } } } } int change(int pre, int num){ if(end[pre]) return -1; int cur = pre; for(int i = 3; i >= 0; --i){ cur = child[cur][(num>>i)&1]; if(end[cur]) return -1; } return cur; } void init_dp(){ for(int i = 0; i <= cnt; ++i){ for(int j = 0; j < 10; ++j){ dp[i][j] = change(i, j); } } } LL dfs(int pos, int sta, bool e, bool z){ if(pos == 0) return 1LL; if(!e && ~f[pos][sta]) return f[pos][sta]; LL res = 0; if(z) res += dfs(pos-1, sta, e&&bit[pos]==0, true); else if(dp[sta][0]!=-1) res += dfs(pos-1, dp[sta][0], e&&bit[pos]==0, false); res %= mod; int u = e ? bit[pos] : 9; for(int d = 1; d <= u; ++d){ if(dp[sta][d]==-1) continue; res += dfs(pos-1, dp[sta][d], e && d==u, false); res %= mod; } if(!e && !z) f[pos][sta] = res; return res; } LL solve(char *str){ int len = strlen(str); for(int i = 0; i < len; ++i){ bit[len-i] = str[i] - '0'; } return dfs(len, 0, 1, 1); } int main(){ int t; scanf("%d", &t); while(t--){ cnt = -1; int root = newNode(); int n; scanf("%d", &n); for(int i = 0; i < n; ++i){ scanf("%s", ch); insert(ch, root); } build_fail(root); init_dp(); memset(f, -1, sizeof(f)); scanf("%s", str); int len = strlen(str); for(int i = len-1; i>=0; --i){ if(str[i]>'0'){ --str[i]; break; } else str[i] = '9'; } LL res = -solve(str); scanf("%s", str); res += solve(str); res = (res + mod) % mod; printf("%lld\n", res); } return 0; }
相关文章推荐
- Permutations II
- PID 在机器人self balance中应用
- SQL Server 索引结构及其使用
- SQL语句――COUNT
- SQL语句――创建表,添加记录
- IOS中的结构体保存到数组与读取
- 白话经典算法系列之——希尔排序的实现
- U盘安装centos 6.3教程(超级详细图解教程) (转)
- windows 绘制窗体时防止闪烁
- 正则表达式语法
- 白话经典算法系列之——直接插入排序的三种实现
- C语言函数指针
- Poisson 分布
- C++多重继承时调用相应的父类函数
- 面向对象设计模式--观察者模式(Observer)
- cocos2d-x 使用action实现各种动画效果 .
- 2013年10月17日 搬出来了
- 收集各种文章资料的URL 不断更新
- CS Coder学习asp.net5个月的最大感悟:从http的角度重新认识asp.net(二)——我理解的ajax(一)
- CS Coder学习asp.net5个月的最大感悟:从http的角度重新认识asp.net(二)——我理解的ajax(一)