https://vjudge.net/problem/UVA-1449
题意
给你n个单词,还有一个长文本s,现在要你输出在文本s中出现次数最多的单词
分析
AC自动机应用之一:统计每个模板串在原字符串中出现的次数
AC自动机的精华:利用last函数,将模板串的所有子串连接起来,只要沿着边走就可以遍历所有模板串的所有子串
对于重复的模板串题目要求重复输出,因此需要对每一个字符串对应一个序号,这就是它们的输入顺序,这样相同的字符串可以有两个不同的序号。实际上不用map。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <ctime> #include <vector> #include <queue> #include <map> #include <stack> #include <set> #include <bitset> using namespace std; typedef long long ll; typedef unsigned long long ull; #define ms(a, b) memset(a, b, sizeof(a)) #define pb push_back #define mp make_pair #define pii pair<int, int> //#define eps 0.0000000001 #define IOS ios::sync_with_stdio(0);cin.tie(0); #define random(a, b) rand()*rand()%(b-a+1)+a #define pi acos(-1) //const ll INF = 0x3f3f3f3f3f3f3f3fll; const int inf = 0x3f3f3f3f; const int maxn = 1e6 + 10; const int maxm = 4e5 +10; const int mod = 20071027; const int sigma_size = 26; struct AC{ int ch[maxn][sigma_size]; int val[maxn]; int last[maxn]; int f[maxn]; int cnt[maxn]; int sz; void init(){ sz=1; memset(ch[0],0,sizeof(ch[0])); memset(cnt,0,sizeof(cnt)); } int idx(char c){ return c-'a'; } void insert(char* s,int v){ int u = 0,n=strlen(s); for(int i=0;i<n;i++){ int c=idx(s[i]); if(!ch[u][c]){ memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; ch[u][c]=sz++; } u=ch[u][c]; } val[u]=v; } void getFail(){ 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.empty()){ int r = q.front();q.pop(); for(int c=0;c<sigma_size;c++){ int u = ch[r][c]; if(!u) { ch[r][c]=ch[f[r]][c]; 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 find(char* T){ int n = strlen(T); int j=0; for(int i=0;i<n;i++){ int c = idx(T[i]); j=ch[j][c]; if(val[j]) print(j); else if(last[j]) print(last[j]); } } void print(int j){ if(j){ cnt[val[j]]++; print(last[j]); } } }; AC ac; char s[maxn],p[155][88]; int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("input.txt", "w", stdout); #endif int n; while(scanf("%d",&n)==1&&n){ ac.init(); for(int i=1;i<=n;i++){ scanf("%s",p[i]); ac.insert(p[i],i); } ac.getFail(); scanf("%s",s); ac.find(s); int bst=-1; for(int i=1;i<=n;i++) bst=max(bst,ac.cnt[i]); printf("%d ",bst); for(int i=1;i<=n;i++){ if(ac.cnt[i]==bst) puts(p[i]); } } return 0; }