【模板】AC自动机(加强版)
题目链接:luogu P3796
题目大意
有一些字符串(互不相同),求哪些字符串在一个大字符串中出现的次数最多。
思路
这道题变了一下,从求有多少个字符串出现过,变成了求哪些字符串出现的次数最多。
那还记得我们之前要记录这个字符串是否出现过吗?
没错,我们就从这里改一下,就我们可以记录这个类型的字符串包含了哪几个,然后就每次发现这种字符串出现在大字符串一次,就给每一个字符串统计一次。
然后最后找最大值,就可以了。
不过好像也可以把相同的字符串合成一个,然后最后变回去就可以,好像内存空间还小一点。
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node {
int num[151], fail;
int son[31];
}tree[20001];
int n, size, now, thi, maxx[151], maxn, sum[151], noww, KK;
char c[1000001], every[151][71];
void getTrie(int nowww) {
size = strlen(c);
now = 0;
for (int i = 0; i < size; i++) {
thi = c[i] - 'a';
if (!tree[now].son[thi]) tree[now].son[thi] = ++KK;
now = tree[now].son[thi];
}
tree[now].num[++tree[now].num[0]] = nowww;//记录哪些字符串是同一个
}
void get_fail() {
queue <int> q;
for (int i = 0; i < 26; i++)
if (tree[0].son[i]) {
tree[tree[0].son[i]].fail = 0;
q.push(tree[0].son[i]);
}
while (!q.empty()) {
now = q.front();
q.pop();
for (int i = 0; i < 26; i++) {
if (tree[now].son[i]) {
tree[tree[now].son[i]].fail = tree[tree[now].fail].son[i];
q.push(tree[now].son[i]);
}
else tree[now].son[i] = tree[tree[now].fail].son[i];
}
}
}
void get_AC() {
size = strlen(c);
now = 0;
for (int i = 0; i < size; i++) {
thi = c[i] - 'a';
now = tree[now].son[thi];
noww = now;
while (noww) {
for (int j = 1; j <= tree[noww].num[0]; j++) {
if (tree[noww].num[j] == 0) continue;
sum[tree[noww].num[j]]++;
if (sum[tree[noww].num[j]] > maxn) {//新的最大
maxn = sum[tree[noww].num[j]];
maxx[0] = 1;
maxx[1] = tree[noww].num[j];
}
else if (sum[tree[noww].num[j]] == maxn) {//原来的最大
maxx[++maxx[0]] = tree[noww].num[j];
}
}
noww = tree[noww].fail;
}
}
}
bool cmp(int x, int y) {//把找到的字符串的位置按照输入的位置排序
return x < y;
}
int main() {
scanf("%d", &n);
while (n) {
memset(tree, 0, sizeof(tree));
memset(sum, 0, sizeof(sum));
memset(maxx, 0, sizeof(maxx));
memset(every, 0, sizeof(every));
KK = 0;
maxn = 0;
for (int i = 1; i <= n; i++) {
scanf("%s", &c);
size = strlen(c);
for (int j = 0; j < size; j++)
every[i][j] = c[j];
getTrie(i);
}
get_fail();
scanf("%s", &c);
get_AC();
printf("%d\n", maxn);
sort(maxx + 1, maxx + maxx[0] + 1, cmp);
for (int i = 1; i <= maxx[0]; i++) {
size = strlen(every[maxx[i]]);
for (int j = 0; j < size; j++)
printf("%c", every[maxx[i]][j]);
printf("\n");
}
scanf("%d", &n);
}
return 0;
}