AC自动机的裸题。学了kmp和Trie以后不难看懂。
有一些变化,比如0的定义和f的指向,和建立失配边,以及多了后缀连接数组last。没有试过把失配边直接当成普通边(一开始还是先这样写吧)。
#include<bits/stdc++.h> using namespace std; const int maxlen = 1e6+5, maxnds = 70*150+100, sigma_size = 26, maxsubs = 151; char str[maxlen]; #define idx(x) x-'a'; int last[maxnds];//后缀连接 为0表示空 int ch[maxnds][sigma_size]; int val[maxnds]; int nds; char subs[maxsubs][80]; int cnt[maxsubs+5]; int f[maxnds]; void init() { memset(ch,0,sizeof(ch)); last[0] = 0; val[0] = 0; nds = 1; memset(cnt,0,sizeof(cnt)); } void cal(int j) { while(j){ cnt[val[j]]++; j = last[j]; } } void Find(char *t) { for(int i = 0, j = 0; t[i] ; i++){ int c = idx(t[i]); while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if(val[j]) cal(j); else if(last[j]) cal(last[j]); } } int getF() { queue<int> q; f[0] = 0; for(int c = 0; c < sigma_size; c++){ int u = ch[0][c]; if(u) { f[u] = 0; q.push(u); last[u] = 0; } } while(q.size()){ int r = q.front(); q.pop(); for(int c = 0; c < sigma_size; c++){ int u = ch[r][c]; if(!u) continue; q.push(u); int v = f[r]; while(v && !ch[v][c]) v = f[v]; f[u] = ch[v][c]; last[u] = val[f[u]] ? f[u] : last[f[u]]; } } } void add(char *s,int str_id) { int u = 0; for(int i = 0; s[i]; i++){ int c = idx(s[i]); if(!ch[u][c]){ memset(ch[nds],0,sizeof(ch[nds])); val[nds] = 0; ch[u][c] = nds++; } u = ch[u][c]; } val[u] = str_id; } int main() { //freopen("in.txt","r",stdin); int n; while(scanf("%d ",&n),n){ init(); for(int i = 1; i <= n; i++){ scanf("%s",subs[i]); add(subs[i],i); } getF(); scanf("%s",str); Find(str); int best = *max_element(cnt+1,cnt+1+n); printf("%d ",best); for(int i = 1; i <= n; i++){ if(cnt[i] == best) puts(subs[i]); } } return 0; }