转换还是比较巧妙的。
因为要求前缀后缀都包含的个数,所以可以把字符串a转换成a#a这样一个字符串,比如abca就转换成abca#abca
然后对于一组前缀a后缀b转换成b#a,比如ab ca,就是ca#ab,
然后对前缀后缀的串建立AC自动机,让主串去匹配,如上述例子,ca#ab满足为abca#abca的一个子串,也就是abca满足这个前缀后缀,所以问题,就转换成了典型的ac自动机匹配问题。
加个#的原因是为了只让后缀#前缀这种串能在AC自动机匹配到。
然后求答案的时候,需要对连接到自己的fail的位置累加一下,含义想一下就明白了。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5+1e5;
char str[maxn];
char *s[maxn];
int d[maxn], pos[maxn], ans[maxn], st[maxn], len[maxn];
char s1[maxn], s2[maxn];
struct acho
{
int nex[maxn+10][29], cnt[maxn+10], fail[maxn+10], match[maxn+10], nl[maxn+10];
int L, root;
int newnode()
{
for(int i=0; i<27; i++)nex[L][i]=-1;
cnt[L++]=0;
fail[L-1]=0;
return L-1;
}
void init()
{
L=0;
root=newnode();
}
int insert(char *a)
{
int now=root, i;
for(i=0; a[i]; i++)
{
if(nex[now][a[i]-'a']==-1)
{
nex[now][a[i]-'a']=newnode();
nl[L-1]=i+1;
}
now=nex[now][a[i]-'a'];
}
cnt[now]=1;
return now;
}
queue<int>que;
void build()
{
while(que.empty()==0)que.pop();
int now=root;
for(int i=0; i<27; i++)
{
if(nex[now][i]==-1)nex[now][i]=root;
else
{
fail[nex[now][i]]=root;
que.push(nex[now][i]);
}
}
while(que.empty()==0)
{
now=que.front();
que.pop();
for(int i=0; i<27; i++)
{
if(nex[now][i]!=-1)
{
que.push(nex[now][i]);
fail[nex[now][i]]=nex[fail[now]][i];
match[nex[now][i]]=cnt[nex[now][i]]?nex[now][i]:match[nex[fail[now]][i]];
}
else
{
nex[now][i]=nex[fail[now]][i];
}
}
}
return;
}
void search(char *a, int len)
{
int i, now=root;
// printf("%s\n", a);
for(i=0; a[i]; i++)
{
now=nex[now][a[i]-'a'];
while(nl[now]>len)
{
now=fail[now];
}
ans[match[now]]++;
// printf("%c %d\n", a[i], now);
}
}
void cal()
{
memset(d, 0, sizeof(int)*(L+1));
int j, k=0, i;
for(i=0; i<L; i++)d[fail[i]]++;
for(i=0; i<L; i++)if(!d[i])st[k++]=i;
for(i=0; i<k; i++)
{
j=fail[st[i]];
ans[j]+=ans[st[i]];
if(!(--d[j]))st[k++]=j;
}
return;
}
}acho;
int main()
{
int t, i, j, n, q;
cin>>t;
while(t--)
{
acho.init();
scanf("%d%d", &n, &q);
j=0;
for(i=0; i<n; i++)
{
s[i]=str+j;
scanf("%s", s[i]);
len[i]=strlen(s[i])+1;
j+=len[i];
strcpy(str+j, s[i]);
str[j-1]='z'+1;
j+=len[i];
}
for(i=0; i<q; i++)
{
scanf("%s%s", s1+1, s2);
s1[0]='z'+1;
strcat(s2, s1);
pos[i]=acho.insert(s2);
// printf("%d ", pos[i]);
}
// printf("\n");
acho.build();
// for(i=0; i<acho.L; i++)printf("%d %d\n", i, acho.match[i]);
for(i=0; i<n; i++)
{
acho.search(s[i], len[i]);
}
acho.cal();
for(i=0; i<q; i++)printf("%d\n", ans[pos[i]]);
for(i=0; i<=acho.L; i++)
{
ans[i]=0;
acho.match[i]=0;
}
}
return 0;
}