题目描述
有N个由小写字母组成的模式串以及一个文本串T。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串T中出现的次数最多。
输入输出格式
输入格式:
输入含多组数据。
每组数据的第一行为一个正整数NN,表示共有NN个模式串,1 ≤ N≤150。
接下去NN行,每行一个长度小于等于70的模式串。下一行是一个长度小于等于106
的文本串T。
输入结束标志为N=0。
输出格式:
对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。
输入输出样例
输入样例#1:
2
aba
bab
ababababac
6
beta
alpha
haha
delta
dede
tata
dedeltalphahahahototatalpha
0
输出样例#1:
4
aba
2
alpha
haha
对于一般的AC自动机模板这样的是统计文本串中有几个单词出现过,因此在模板中我们跳fail指针的时候会有这样一句话
for(int j = now; j && cd[j] != -1; j = f[j]){//cd[]表示改点为几个模式串的结尾
ans += cd[j];
cd[j] = -1;//防止重复判断累加答案
}
这里我们为了避免一个单词出现多次导致我们答案加了一遍以上,因此我们在每次加过后都将其赋为-1了,但是本题中要我们统计出现最多的单词,所以不需要这句话。
我们可以一个统计模式串出现次数的数组在每次跳到单词结尾的时候,让其加一。
最后跳完比较一下,输出答案就行。
这道题的数据比较大,用cin应该会挂掉,但我挂掉主要不是因为这个(这说起来就是一把辛酸泪了),反正就是我写了字符串的快读,用scanf应该也行,不够在定义函数时里面的int(sting s)要改成int(char a[]);其他的一些操作也要改一下。
注意: 因为是多组数据,所以每次都要将有关的数组清空,用memset就行,别老想着自己手动for循环清,我被这个卡了一天T.T。 当然,菜是原罪。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 * 4 + 5;
int trie[MAXN][28];
int cd[MAXN];
int fail[MAXN];
int n, cnt = 0;
inline string read(){
char ch = getchar();
string st1 = "";
while(!(ch >= 'a' && ch <= 'z')) ch = getchar();
while(ch >= 'a' && ch <= 'z') st1 += ch, ch = getchar();
return st1;
}
struct node{
int num, pos;
}v[MAXN];
bool operator<(node a, node b){
if(a.num != b.num)
return a.num > b.num;
else return a.pos < b.pos;
}
inline void clean(){
memset(trie, 0, ++cnt * 104);
for(int i = 1; i <= n; ++i) cd[i] = 0, v[i] = node{0, 0};
for(int i = 1; i <= cnt; ++i) fail[i] = 0;
}
void insert(string s, int a){
int root = 0;
for(int i = 0; i < s.size(); ++i){
int nt = s[i] - 'a' + 1;
if(!trie[root][nt]) trie[root][nt] = ++cnt;
root = trie[root][nt];
}
cd[root] = a;
}
void find_fail(){
queue < int > q;
for(int i = 1; i <= 26; ++i){
int x = trie[0][i];
if(x) fail[x] = 0, q.push(x);
}
while(!q.empty()){
int x = q.front(); q.pop();
for(int i = 1; i <= 26; ++i){
if(trie[x][i]) {
fail[trie[x][i]] = trie[fail[x]][i];
q.push(trie[x][i]);
}
else trie[x][i] = trie[fail[x]][i];
}
}
}
int q(string s){
int now = 0, ans = 0;
for(int i = 0; i < s.size(); ++i){
now = trie[now][s[i] - 'a' + 1];
for(int j = now; j && cd[j] != -1; j = fail[j]){
v[cd[j]].num ++;
// cout<<1<<endl;
}
}
return ans;
}
string s[100010];
int main()
{
while(12345679){
// cout << '!' << endl;
scanf("%d", &n);
if(n == 0) break;
clean();
for(int i = 1; i <= n; ++i){
s[i] = read();
v[i].num = 0;
v[i].pos = i;
insert(s[i], i);
}
find_fail();
s[0] = read();
int ans = q(s[0]);
sort(&v[1], &v[n + 1]);
printf("%d\n", v[1].num);
cout << s[v[1].pos] << endl;
for(int i = 2; i <= n; ++i){
// cout << 1 <<endl;
if(v[i].num == v[i - 1].num)
cout << s[v[i].pos] << endl;
else break;
}
}
return 0;
}