/**//* 问A到B之间的所有整数,转换成BCD Code后,有多少个不包含属于给定非法01串集合的子串。 0 < A ≤ B < 10^200
统计问题,这里我用之前的那种写法,还是比较方便的 http://www.cppblog.com/Yuan/archive/2011/01/25/139299.html
参考watashi的 由于需要判定合不合法,需要构造ac自动机 然后预处理下,将每一步01处理成每一步是走0..9,非法(即不可走的)指针就为-1了 然后状态就是 (root, pos, bound) 表示前面已经走到了节点root,当前要检查digit数组的第pos位,bound表示是否有上界, bound为false表示木有,即该位置可枚举0..9 然后就是记忆化搜索了 注意处理前置0,这里多加了一维,表示前缀是否都是0 */ #include<iostream> #include<cstring> #include<map> #include<algorithm> #include<stack> #include<queue> #include<cmath> #include<string> #include<cstdlib> #include<vector> #include<cstdio> #include<set> #include<list> #include<numeric> #include<cassert> #include<ctime> #include<bitset>
using namespace std;
struct AhoCorasick { static const int UNDEF = 0; static const int MAXN = 2048; static const int CHARSET = 2;
int end; int tag[MAXN]; int fail[MAXN]; int trie[MAXN][CHARSET]; int next[MAXN][10];
int newNode() { tag[end] = UNDEF; fill(trie[end], trie[end] + CHARSET, -1); return end ++; }
void init() { end = 0; newNode(); } void insert(int root, char *s) { if(*s == 0){ tag[root] = 1; return; } if(trie[root][*s-'0'] == -1){ trie[root][*s-'0'] = newNode(); } insert(trie[root][*s-'0'], s+1); } void build() { queue<int> bfs; fail[0] = 0; for( int i = 0 ; i < CHARSET ; i ++) { if(trie[0][i] != -1){ fail[trie[0][i]] = 0; bfs.push(trie[0][i]); } else { trie[0][i] = 0; } } while(!bfs.empty()) { int p = bfs.front(); tag[p] |= tag[fail[p]]; // bfs.pop(); for(int i = 0 ; i < CHARSET; i ++) { if (trie[p][i] != -1) { fail[trie[p][i]] = trie[fail[p]][i]; bfs.push(trie[p][i]); } else { trie[p][i] = trie[fail[p]][i]; } } } }
int calNext(int p , int x) { if(tag[p] == 1){ return -1; } for(int i = 3; i >= 0 ; i --) { p = trie[p][(x>>i)&1]; if(tag[p] == 1){ return -1; } } return p; }
void calNext() { for( int i = 0 ; i < end ; i++) { for (int j = 0 ; j <= 9 ; j++){ next[i][j] = calNext(i,j); } } } } ac;
const long long MOD = 1000000009LL;
long long dp[AhoCorasick::MAXN][250];//不是AhoCorasick.MAXN int digit[250];
long long dfs(int root, int pos , bool bound, bool preIsZero) { if(pos == -1) { return 1LL; } if( dp[root][pos] != -1 && !bound){ return dp[root][pos]; } long long ans = 0; int end = bound ? digit[pos] : 9;
//deal with zero if(preIsZero && pos > 0) { //该位仍是前缀0 下面这个也即为false了 ans += dfs(root, pos - 1, bound && end == 0, true); } else { if(ac.next[root][0] != -1 && ac.tag[ac.next[root][0]] == 0 ) { ans += dfs(ac.next[root][0], pos - 1, bound && end == 0, false); } }
for(int i = 1; i <= end ; i ++ ) { if(ac.next[root][i] != -1 && ac.tag[ac.next[root][i]] == 0 ) { ans += dfs(ac.next[root][i], pos-1, bound && i == end, false); } } ans %= MOD; if(!bound) { dp[root][pos] = ans; } return ans; }
long long gao(char *s) {//cal the legal number in [0,s] int len = strlen(s); for(int i = len - 1 ; i >= 0 ; i -- ){ digit[len - 1 - i] = s[i] - '0'; } return dfs(0, len-1, true, true); }
int main() {
#ifndef ONLINE_JUDGE freopen("in","r",stdin); #endif
int T, n; char str[250] , *p; for (scanf("%d", &T); T--; ) { ac.init(); for (scanf("%d", &n); n -- ; ) { scanf("%s", str); ac.insert(0, str); } ac.build(); ac.calNext();
memset(dp, -1, sizeof dp); long long ans = 0; //A p = str; scanf("%s", p); for (int i = strlen(p) - 1 ; i >= 0 ; i-- ){ if(p[i] == '0'){ p[i] = '9'; } else { p[i] --; break; } } if(*p == '0' && *(p+1) != 0){ p++; } ans -= gao(p);
//B p = str; scanf("%s", p); ans += gao(p);
printf("%lld\n", (ans+MOD)%MOD); } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|