ZOJ 3228

ZOJ - 3228

先把模板串都丢进AC自动机

然后跑查询

对于允许重叠的,我们直接对\(fail\)树上一段路径的节点的答案++

否则我们分串的长度讨论,对于每种长度的串处理一个答案\(dp[i][6]\)

int n;
char s[N][10],str[N];
int kind[N],End[N];
const int SIZE=N*6;
int dp[SIZE][7],pre[SIZE][7];

namespace AC{
	int trie[SIZE][26];
	int fail[SIZE],cnt;
	void clear(){ 
		cnt=0;
		memset(trie,0,sizeof trie);
	}
	int Insert(char *s){ 
		int p=0;
		rep(i,0,strlen(s)-1) {
			int x=s[i]-'a';
			((!trie[p][x])&&(trie[p][x]=++cnt));
			p=trie[p][x];
		}
		return p;
	}
	void Build(){
		static queue <int> que;
		rep(i,0,25) if(trie[0][i]) {
			que.push(trie[0][i]);
			fail[trie[0][i]]=0;
		}
		while(!que.empty()) {
			int u=que.front(); que.pop();
			rep(i,0,25) {
				int &v=trie[u][i];
				if(v) {
					fail[v]=trie[fail[u]][i];
					que.push(v);
				} else v=trie[fail[u]][i];
			}
		}
	}
	void Que(char *s) {
		memset(dp,0,sizeof dp);
		memset(pre,-63,sizeof pre);
		int p=0;
		rep(i,0,strlen(s)-1) {
			p=trie[p][s[i]-'a'];
			for(reg int j=p; j; j=fail[j]) {
				dp[j][0]++;
				rep(k,1,6) {
					if(i-pre[j][k]>=k) {
						dp[j][k]++;
						pre[j][k]=i;
					}
				}
			}
		}
	}
}



int main(){
	int kase=0;
	while(~scanf("%s",str)) {
		printf("Case %d\n",++kase);
		AC::clear();
		n=rd();
		rep(i,1,n) {
			kind[i]=rd();
			scanf("%s",s[i]);
			if(kind[i]) kind[i]=strlen(s[i]);
			End[i]=AC::Insert(s[i]);
		}
		AC::Build();
		AC::Que(str);
		rep(i,1,n) printf("%d\n",dp[End[i]][kind[i]]);
		puts("");
	}
}
原文地址:https://www.cnblogs.com/chasedeath/p/12931249.html