【Aho-Corasick Automaton】

ZOJ 3494 BCD Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int each[10][4] = {0,0,0,0, 0,0,0,1, 0,0,1,0, 0,0,1,1, 0,1,0,0, 0,1,0,1, 0,1,1,0, 0,1,1,1, 1,0,0,0, 1,0,0,1};
const int N = 100, L = 21, T = 2, M = 205;
const int ND = N*L;
const int MOD = 1000000009;

int str[N][L], pa[M], pb[M];
int n;

int next[ND][T], fail[ND], acc[ND], B[ND], cnt;

int step[ND][10], total[M][ND], non[M];

void read(int *f){
	char c; while(c=getchar(), c<'0'||c>'9');
	f[f[0]=1] = c-'0'; while(c=getchar(), c>='0'&&c<='9') f[++f[0]] = c-'0';
}

void init(){
	
	scanf("%d", &n);
	for(int i=0; i<n; i++) read(str[i]);
	read(pa); read(pb);
	
}

void construct(){
	
	cnt = 0;
	memset(next, 0, sizeof(int)*ND*T);
	memset(fail, 0, sizeof(int)*ND);
	memset(acc, 0, sizeof(int)*ND);
	
	for(int i=0, p, j; i<n; i++){
		for(p=0, j=1; j<=str[i][0]; j++) if(next[p][str[i][j]]) p = next[p][str[i][j]];
		else next[p][str[i][j]] = ++cnt, p = cnt;
		acc[p] = 1;
	}
	
	int hd(0), tl(0);
	for(int i=0; i<T; i++) if(next[0][i]) B[++tl] = next[0][i];
	
	while(hd<tl){
		int x = B[++hd]; acc[x] |= acc[fail[x]];
		for(int i=0; i<T; i++) if(next[x][i]){
			fail[next[x][i]] = next[fail[x]][i];
			B[++tl] = next[x][i];
		} else next[x][i] = next[fail[x]][i];
	}
	
}

void reverse(int *f){ for(int i=1; i<=f[0]/2; i++) swap(f[i], f[f[0]-i+1]); }

void dec(int *f){
	int last = 1; while(!f[last]) ++last;
	for(int i=1; i<last; i++) f[i] = 9; f[last]--;
	if(f[f[0]]==0) --f[0];
}

void predp(int x){
	
	/* step */
	for(int i=0; i<=cnt; i++){
		for(int num=0, p, j; num<10; num++) {
			for(p=i, j=0; j<4 && !acc[p]; j++) p = next[p][each[num][j]];
			step[i][num] = p;
		}
	}
	
	/*total*/
	memset(total, 0, sizeof(int)*M*ND);
	for(int i=0; i<=cnt; i++) total[0][i] = !acc[i];
	for(int ci=1; ci<=x; ci++) {
		for(int i=0; i<=cnt; i++) if(!acc[i]) {
			for(int num=0; num<10; num++) total[ci][i] = (total[ci][i] + total[ci-1][step[i][num]]) % MOD;
		}
	}
	
	/*non*/
	non[0] = 0;
	for(int i=1; i<=x; i++){
		non[i] = ((non[i-1] + total[i][0])%MOD - total[i-1][step[0][0]]) % MOD;
	}
	
}

int dp(int *f){
	
	int ret(non[f[0]-1]), p=0;
	
	for(int i=f[0]; i; i--){
		for(int num = (i==f[0])? 1 : 0;  num < f[i]; num++ ) ret = (ret + total[i-1][step[p][num]]) % MOD;
		p = step[p][f[i]];
		if(acc[p]) break;
	}
	
	if(f[0]==0) ret = (ret + total[0][step[0][0]]) % MOD;
	else  ret = ((ret + total[0][p])%MOD + total[0][step[0][0]])%MOD;
	
	return ret;
	
}

void maindo(){
	
	reverse(pa), reverse(pb);
	
	dec(pa);
	
	predp(pb[0]);
	int ans = ((dp(pb) - dp(pa)) % MOD + MOD ) % MOD;
	printf("%d\n", ans);
	
}

void work(){
	
	init();
	construct();
	maindo();
	
}

int main(){
	
	freopen("bcd.in", "r", stdin);
	freopen("bcd.out", "w", stdout);
	
	int Tes;
	scanf("%d", &Tes);
	while(Tes-->0) work();
	
	return 0;
	
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值