ZOJ 3494 BCD Code (AC自己主动机 + 数位DP)
题目链接:BCD Code
解析:n个病毒串。问给定区间上有多少个转换成BCD码后不包括病毒串的数。
很奇妙的题目。
。
经典的 AC自己主动机 + 数位DP 的题目。
首先使用AC自己主动机,得到bcd[i][j]表示状态i,加了数字j以后到达的状态。为-1表示不能转移
然后就是数位DP了
注意记录为0的状态
AC代码:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> using namespace std; struct Trie{ int next[2010][2], fail[2010]; bool end[2010]; int root, L; int newnode(){ for(int i=0; i<2; i++) next[L][i] = -1; end[L++] = false; return L-1; } void init(){ L = 0; root = newnode(); } void insert(char buf[]){ int len = strlen(buf); int now = root; for(int i=0; i<len; i++){ if(next[now][buf[i] - '0'] == -1) next[now][buf[i] - '0'] = newnode(); now = next[now][buf[i] - '0']; } end[now] = true; } void build(){ queue<int> Q; fail[root] = root; for(int i=0; i<2; i++) if(next[root][i] == -1) next[root][i] = root; else{ fail[ next[root][i] ] = root; Q.push(next[root][i]); } while(!Q.empty()){ int now = Q.front(); Q.pop(); if(end[ fail[now] ]) end[now] = true; for(int i=0; i<2; i++) if(next[now][i] == -1) next[now][i] = next[ fail[now] ][i]; else{ fail[ next[now][i] ] = next[ fail[now] ][i]; Q.push(next[now][i]); } } } }; Trie ac; char buf[210]; int bcd[2010][10]; int change(int pre, int num){ if(ac.end[pre]) return -1; int cur = pre; for(int i=3; i>=0; i--){ if(ac.end[ac.next[cur][(num>>i)&1]]) return -1; cur = ac.next[cur][(num>>i)&1]; } return cur; } void pre_init(){ for(int i=0; i<ac.L; i++) for(int j=0; j<10; j++) bcd[i][j] = change(i, j); } const int MOD = 1000000009; long long dp[210][2010]; int bit[210]; long long dfs(int pos, int s, bool flag, bool z){ if(pos == -1) return 1; if(!flag && dp[pos][s] != -1) return dp[pos][s]; long long ans = 0; if(z){ ans += dfs(pos-1, s, flag && bit[pos] == 0, true); ans %= MOD; } else{ if(bcd[s][0] != -1) ans += dfs(pos-1, bcd[s][0], flag && bit[pos] == 0, false); ans %= MOD; } int _end = (flag ? bit[pos] : 9); for(int i=1; i<=_end; i++){ if(bcd[s][i] != -1){ ans += dfs(pos-1, bcd[s][i], flag && i == _end, false); ans %= MOD; } } if(!flag && !z) dp[pos][s] = ans; return ans; } long long calc(char s[]){ int len = strlen(s); for(int i=0; i<len; i++) bit[i] = s[len-1 - i] - '0'; return dfs(len-1, 0, true, true); } int main(){ #ifdef sxk freopen("in.txt", "r", stdin); #endif // sxk int T; int n; scanf("%d", &T); while(T--){ ac.init(); scanf("%d", &n); for(int i=0; i<n; i++){ scanf("%s", buf); ac.insert(buf); } ac.build(); pre_init(); memset(dp, -1, sizeof(dp)); int ans = 0; scanf("%s", buf); int len = strlen(buf); for(int i=len-1; i>=0; i--){ if(buf[i] > '0'){ buf[i] --; break; } else buf[i] = '9'; } ans -= calc(buf); ans %= MOD; scanf("%s", buf); ans += calc(buf); ans %= MOD; if(ans < 0) ans += MOD; printf("%d\n", ans); } return 0; }