/************
AC自动机 + 数位dp
好题!
给出一些模式串,求区间内不出现这些串的数字串的个数
以这些模式串构建AC自动机,
建自动机的时候要注意记录好结束状态
预处理出所有状态加上某个数字后的状态,在数位枚举每一位上数字的
时候,直接推出下一个状态。
特别要注意的是前导0的情况,当前面全是0的时候而且当前位也是0的时候,
就可以当成初始状态来处理。
****************/
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 500010
struct Trie{
int next[maxn][2],fail[maxn];
bool end[maxn];
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 str[]){
//printf("insert:%s\n",str);
int len = strlen(str);
int now = root;
for(int i=0;i<len;i++){
int temp = str[i] - '0';
if(next[now][temp] == -1){
next[now][temp] = newNode();
}
now = next[now][temp];
}
end[now] = true;
}
void build(){
queue<int> que;
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;
que.push(next[root][i]);
}
}
while(!que.empty()){
int now = que.front();
que.pop();
if(end[fail[now]]) end[now] = true;
for(int i=0;i<2;i++){
int t = next[now][i];
if(t==-1){
next[now][i] = next[fail[now]][i];
}else{
fail[t] = next[fail[now]][i];
//printf("id:%d fail:%d\n",t,fail[t]);
que.push(t);
}
}
}
}
void debug(){
for(int i=0;i<L;i++){
printf("id:%3d fail:%3d end:%3d next:[",i,fail[i],end[i]);
for(int j=0;j<26;j++){
printf(" %2d",next[i][j]);
}
printf("]\n");
}
}
}ac;
typedef long long LL;
const int mod = 1000000009;
char buf[250];
int next[2010][20];
LL dp[250][2010];
int p[250];
int change(int s,int k){
if(ac.end[s]) return -1;
for(int i=3;i>=0;i--){
if(ac.end[ac.next[s][(k>>i)&1]]) return -1;
s = ac.next[s][(k>>i)&1];
}
return s;
}
void pre_solve(){
for(int i=0;i<ac.L;i++){
for(int j=0;j<10;j++){
next[i][j] = change(i,j);
//printf("i:%d j:%d %d\n",i,j,next[i][j]);
}
}
}
LL dfs(int h,int s,bool flag, bool zero){
if(h==-1) return 1;
if(!flag && dp[h][s]!=-1) return dp[h][s];
LL res = 0;
if(zero){
res += dfs(h-1,s,flag && p[h]==0,true);
res %= mod;
}else{
if(next[s][0]!=-1) res += dfs(h-1,next[s][0], flag && p[h]==0, false);
res %= mod;
}
int up = flag?p[h]:9;
for(int i=1;i<=up;i++){
if(next[s][i] == -1) continue;
res += dfs(h-1,next[s][i],flag&&i==up,false);
res %= mod;
}
if(!flag && !zero) dp[h][s] = res;
return res;
}
LL solve(char s[]){
int len = strlen(s);
for(int i=0;i<len;i++) p[i] = s[len-i-1] - '0';
return dfs(len-1,0,true,true);
}
int main(){
int T,n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
ac.init();
memset(dp,-1,sizeof(dp));
while(n--){
scanf("%s",buf);
ac.insert(buf);
}
ac.build();
// ac.debug();
pre_solve();
scanf("%s",buf);
int len = strlen(buf);
for(int i=len-1;i>=0;i--){
if(buf[i] == '0') buf[i] = '9';
else {
buf[i]--;
break;
}
}
LL ans = -solve(buf);
scanf("%s",buf);
ans += solve(buf);
ans = (ans%mod + mod)%mod;
cout << ans << endl;
}
return 0;
}
zoj 3494 BCD Code AC自动机 + 数位dp
最新推荐文章于 2019-11-25 21:56:22 发布