题目链接:Searching the String
解析:给一个长串。给n个不同种类的短串。问分别在能重叠下或者不能重叠下短串在长串中出现的次数。
能重叠的已经是最简单的AC自己主动机模板题了。
不能重叠的记录一下每一个匹配的串的起始位置保证不重叠就可以。
AC代码:
#include <bits/stdc++.h> using namespace std; struct Trie{ int next[600010][26], fail[600010], deep[600010]; int root, L; int newnode(){ for(int i = 0; i < 26; i++) next[L][i] = -1; L ++; return L-1; } void init(){ L = 0; root = newnode(); deep[root] = 0; } int insert(char buf[]){ int len = strlen(buf); int now = root; for(int i = 0; i < len; i++){ if(next[now][ buf[i] - 'a' ] == -1){ next[now][ buf[i] - 'a' ] = newnode(); deep[next[now][buf[i] - 'a']] = i+1; } now = next[now][ buf[i] - 'a' ]; } return now; } void build(){ queue<int> Q; fail[root] = root; for(int i = 0; i < 26; i++){ if(next[root][i] == -1) next[root][i] = root; else{ fail[ next[root][i] ] = root; Q.push(next[root][i]); } } while(!Q.empty()){ int now = Q.front(); Q.pop(); for(int i = 0; i < 26; i++){ if(next[now][i] == -1) next[now][i] = next[ fail[now] ][i]; else{ fail[ next[now][i] ] = next[ fail[now] ][i]; Q.push(next[now][i]); } } } } int cnt[600010][2]; //cnt[][0]表示能重叠的,cnt[][1]表示不能重叠的 int last[600010]; //上次匹配的字符 void query(char buf[]){ memset(cnt, 0, sizeof(cnt)); memset(last, -1, sizeof(last)); int len = strlen(buf); int now = root; for(int i = 0; i < len; i++){ now = next[now][ buf[i] - 'a' ]; int temp = now; while(temp != root){ cnt[temp][0] ++; if(i - last[temp] >= deep[temp]){ //保证不重叠 last[temp] = i; cnt[temp][1] ++; } temp = fail[temp]; } } } }; char buf[20]; char str[100010]; int typ[100010], pos[100010]; Trie ac; int main(){ #ifdef sxk freopen("in.txt", "r", stdin); #endif //sxk int n; int kase = 0; while(scanf("%s", str) == 1){ scanf("%d", &n); ac.init(); for(int i = 0; i < n; i++){ scanf("%d%s", &typ[i], buf); pos[i] = ac.insert(buf); } ac.build(); ac.query(str); printf("Case %d\n", ++kase); for(int i=0; i<n; i++) printf("%d\n", ac.cnt[pos[i]][typ[i]]); printf("\n"); } return 0; }