>Link
luogu P3796
>解题思路
其实这道题就是AC自动机朴素版的改编,找到一个子串时就标记下来,记录下每一个子串对应出现的个数,最后取最大值就行了
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 100010
using namespace std;
queue<int> Q;
int n, cnt, p, nxt[N], sum[N], t[N][30], ed[N], num[N];
int T, maxn, ans[N];
string a[N], s;
void build_trie ()
{
for (int i = 1; i <= n; i++)
{
cin >> a[i];
int len = a[i].size();
p = 0;
for (int j = 0; j < len; j++)
{
int x = a[i][j] - 'a' + 1;
if (!t[p][x]) t[p][x] = ++cnt;
p = t[p][x];
}
ed[p]++;
num[i] = p; //存当前子串在trie中的位置
}
}
void get_fail ()
{
for (int i = 1; i <= 26; i++)
{
if (!t[0][i]) continue;
Q.push(t[0][i]);
nxt[t[0][i]] = 0;
}
while (!Q.empty())
{
int u = Q.front();
Q.pop();
for (int i = 1; i <= 26; i++)
{
if (!t[u][i])
t[u][i] = t[nxt[u]][i];
else
{
Q.push(t[u][i]);
nxt[t[u][i]] = t[nxt[u]][i];
}
}
}
}
void ACauto ()
{
cin >> s;
int len = s.size();
s = " " + s;
p = 0;
for (int i = 1; i <= len; i++)
{
int x = s[i] - 'a' + 1;
p = t[p][x];
int v = p;
while (v) //不能这个位置走过就不走了,因为我们要记录的是子串出现的次数
{
sum[v]++; //在节点位置记录
v = nxt[v];
}
}
}
int main()
{
scanf ("%d", &n);
while (n != 0)
{
cnt = maxn = 0;
memset (t, 0, sizeof (t));
memset (ed, 0, sizeof (ed));
memset (nxt, 0, sizeof (nxt));
memset (sum, 0, sizeof (sum));
memset (ans, 0, sizeof (ans));
memset (num, 0, sizeof (num));
build_trie ();
get_fail ();
ACauto ();
for (int i = 1; i <= n; i++)
if (sum[num[i]] > maxn)
{
maxn = sum[num[i]];
ans[ans[0] = 1] = i;
}
else if (sum[num[i]] == maxn)
ans[++ans[0]] = i;
printf ("%d\n", maxn);
for (int i = 1; i <= ans[0]; i++)
cout << a[ans[i]] << endl;
scanf ("%d", &n);
}
return 0;
}