题目链接:String
题意:给定
N
字符串以及
题解:把每一个询问以“后缀+‘{’+前缀”形式连接起来组成新的字符串,并用这些字符串构成AC自动机,同时记录原询问的长度,最后把原来的
N
<script type="math/tex" id="MathJax-Element-200">N</script>个字符串在AC自动机中跑一遍记录长度满足条件的就能得到答案。由于可能有相同的询问,所以可以利用map或者并查集去重,最后输出答案时处理一下即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 1000100;
struct Aho{
int nxt[27],fail,info,lim,cnt;
void init(){
fill(nxt,nxt+27,0);
fail=info=cnt=0;
}
}a[N];
int id,q[N],ans[N/10],f[N/10];
int Find(int x){
int r=x;
while(f[x]!=x)
x=f[x];
f[r]=x;
return x;
}
void Merge(int x,int y){
x=Find(x);
y=Find(y);
if(x!=y)
f[x]=y;
}
void Ist(const string& s,int ps){
// cout<<"Insert: "<<s<<' '<<ps<<endl;
int now=0,len=s.size();
for(int i=0;i<len;i++){
int t=s[i]-'a';
if(a[now].nxt[t])
now=a[now].nxt[t];
else{
a[++id].init();
a[now].nxt[t]=id;
now=id;
}
}
if(a[now].info)
Merge(ps,a[now].info);
a[now].info=ps;
a[now].lim=len;
a[now].cnt=1;
}
void Build(){
int now,t,head=0,tail=0;
q[tail++]=0;
a[0].fail=0;
while(head!=tail){
now=q[head++];
for(int i=0;i<27;i++)
if(a[now].nxt[i]){
for(t=a[now].fail;t&&!a[t].nxt[i];t=a[t].fail);
if(now)
a[a[now].nxt[i]].fail=a[t].nxt[i];
q[tail++]=a[now].nxt[i];
}
}
}
void Match(const string& s){
int len=s.size(),now=0,t,k;
for(int i=0;i<len;i++){
t=s[i]-'a';
for(;now&&!a[now].nxt[t];now=a[now].fail);
now=a[now].nxt[t];
for(k=now;k;k=a[k].fail){
if((len-1)/2>=a[k].lim-1)
ans[Find(a[k].info)]+=a[k].cnt;
}
}
}
vector<string>v;
string t,tt;
int main(){
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--){
int n,q;
cin>>n>>q;
v.clear();
id=0;
a[0].init();
for(int i=1;i<=n;i++){
cin>>t;
t=t+"{"+t;
v.push_back(t);
}
for(int i=1;i<=q;i++)
f[i]=i;
for(int i=1;i<=q;i++){
cin>>t>>tt;
t=tt+"{"+t;
Ist(t,i);
}
Build();
memset(ans,0,sizeof ans);
for(int i=0;i<v.size();i++)
Match(v[i]);
for(int i=1;i<=q;i++)
printf("%d\n",ans[Find(i)]);
}
return 0;
}