zerojudge 空罐 Cans

AC 自动机+DP……F[L][J]表示长度为L的基因在J的位置的个数。因为基因要变短,转移时要讨论L是否小于J位置串长度,转移到fail指针的位置。

(因为一个白痴错误debug了一个晚上……切记要转移病毒中的病毒啊!)

#include <iostream>
#include <cstring>
using namespace std;

#define CC(A,x)		memset(A, x, sizeof(A))
#define FOR(i,n)	for(int i=0; i<n; i++)

const int NN=2000, CH=4, MOD=10007;
struct Trie{
	inline int sw(char *c){return *c-'a';}
	void init(){CC(chd,0); CC(F,0); CC(W,0); sz=1;}
	void insert(char *s, int val){
		int p=0, dis=0;
		for (; *s; p=chd[p][sw(s++)]){
			if (!chd[p][sw(s)]) chd[p][sw(s)]=sz++;
			D[p] = dis++;
		}
		W[p]=val; D[p]=dis;
	}
	void AC(){
		int Q[NN], *b=Q, *e=Q, v;
		FOR(i,CH) if (v=chd[0][i]) *e++ = v;
		for (int p=*b; b!=e; p=*++b)
			FOR(i,CH) if (v=chd[p][i]){
				F[*e++ = v] = chd[F[p]][i];
				if (W[F[v]]) W[v]=1;
			}else chd[p][i] = chd[F[p]][i];
	}
	int find(char *s){
		int p = 0;
		for (; *s; p=chd[p][sw(s++)]);
		return p;
	}
	int chd[NN][CH], F[NN], W[NN], D[NN], sz;
}trie;


int P, N;
char str[256], ss[32];

void Input(){
	trie.init();
	cin>>str>>P>>N;
	FOR(i,N) {
		cin>>ss;
		trie.insert(ss, 1);
	}
	trie.AC();
}

int F[2][110][NN]={0}, S=0, D=1;
void DP(){
	int pos = trie.find(str);
	int len = strlen(str);
	F[S][len][pos] = 1;

	if (trie.W[pos]) {cout<<"0 1"<<endl; return;}

	int old=0, ill=0, add;
	while (P--){
		CC(F[D], 0);
		FOR(j, trie.sz){
			if (trie.W[j]) continue;
			for(int L=1; L<=100; L++){
				if ((add=F[S][L][j]) == 0) continue;
				FOR(k,CH){
					int son = trie.chd[j][k];
					F[D][L+1][son] += add;
					F[D][L+1][son] %= MOD;
					if (trie.W[son]){
						ill+=add, ill%=MOD;
					}
				}
				if (L == 1){
					old += add;
					old %= MOD;
				}else if (L <= trie.D[j]){
					int x = trie.F[j];
					F[D][L-1][x] += add;
					F[D][L-1][x] %= MOD;
				}else{
					F[D][L-1][j] += add;
					F[D][L-1][j] %= MOD;
				}
			}
		}
		D=S; S=1-S;
	}
	cout<<old<<" "<<ill<<endl;
}

int main()
{
	Input();
	DP();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值