题目链接:传送门
题意分析:
先给你一个长度为n的模式串,然后给你m个匹配串,让你求出m个匹配串中每个匹配串在模式串中不重叠的个数。
题目分析:
如果只是一个匹配串,那当然就用KMP了,多个匹配串,这不就是AC自动机的模板嘛。但有一个问题,就是不能重叠。解决这个问题很简单,把结果开成2维的,如ans[m][2], 其中ans[i][0]表示上第i个匹配串的答案,ans[i][1]表示第i个匹配串表示上一个记录答案的位置,那样的话,就可以通过(i - ans[d][1]+1) >= le[d]特判是否有贡献,其中i表示模式串的位置,d表示第几个匹配串。还有注意的是,因为匹配串可以相同的,所以要用到哈希处理一下。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
string s, str;
char te[maxn];
int ans[maxn][3];
map<string, int>ma;
int ha[maxn];
int le[maxn];
struct node
{
int cnt;
node *next[26], *fail;
node(){
cnt = 0;
fail = NULL;
memset(next, NULL, sizeof(next));
}
}*q[maxn], *root;
void insert1(char* s, node *p, int d)
{
int i = 0, k;
p = root;
while(s[i]){
k = s[i++]-'a';
if(p->next[k] == NULL) p->next[k] = new node();
p = p->next[k];
}
p->cnt = d;
}
void build(node *root)
{
int i, head=0, tail=1;
q[head] = root;
node *p, *temp;
while(head < tail){
temp = q[head++];
for(i=0;i<26;++i){
if(temp->next[i]){
if(temp == root) temp->next[i]->fail = root;
else{
p = temp->fail;
while(p){
if(p->next[i]) {
temp->next[i]->fail = p->next[i];
break;
}
p = p->fail;
}
if(!p) temp->next[i]->fail = root;
}
q[tail++] = temp->next[i];
}
}
}
}
void query(char* s, node *root)
{
int k, len = strlen(s);
node *p = root;
for(int i=0;i<len;++i){
k = s[i]-'a';
while(!p->next[k] && p != root) p = p->fail;
p = p->next[k];
if(!p) p = root;
node *temp = p;
while(temp != root){
int d = temp->cnt;
if( (i - ans[d][1]+1) >= le[d]) {
ans[d][0]++;
ans[d][1] = i+1;
}
temp = temp->fail;
}
}
}
int main()
{
int t, n;
memset(ans, 0, sizeof(ans));
scanf("%d %d", &t, &n);
cin >> s;
root = new node;
for(int i=1;i<=n;++i){
cin >> str;
le[i] = str.length();
if(ma[str]) ha[i] = ma[str];
else{
ma[str] = i;
ha[i] = i;
insert1((char*)str.c_str(), root, i);
}
}
build(root);
query((char*)s.c_str(), root);
for(int i=1;i<=n;++i){
cout << ans[ha[i]][0] << endl;
}
return 0;
}