P9196 JOI Open 2016 销售基因链 / Selling RNA Strands 题解
思路
考虑映射,将基因库的字符串 SiS_iSi 映射成 Si#SiS_i\#S_iSi#Si 的形式,对于询问 P,QP,QP,Q 映射成 Q#PQ\#PQ#P 的形式,那么就相当于问每个询问串在基因库中出现的次数,直接跑 AC 自动机多模匹配即可。
代码
cpp
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
int ch[5000010][5],ed[5000010],fail[5000010],c[255],id;
int ip[100010];
void ins(string s,int x){
int p=0;
for(int i=0;i<s.size();i++){
int j=c[s[i]];
if(!ch[p][j])ch[p][j]=++id;
p=ch[p][j];
}
ip[x]=p;
}
int q[4100010],l=1,r;
void build(){
for(int i=0;i<5;i++)if(ch[0][i])q[++r]=ch[0][i];
while(l<=r){
int x=q[l++];
for(int i=0;i<5;i++){
int &y=ch[x][i];
if(!y)y=ch[fail[x]][i];
else fail[y]=ch[fail[x]][i],q[++r]=y;
}
}
}
vector<int> G[5000010];
void query(string s){
int p=0;
for(int i=0;i<s.size();i++){
int j=c[s[i]];
p=ch[p][j];
ed[p]++;
}
}
void dfs(int x){
for(int y:G[x]){
dfs(y);
ed[x]+=ed[y];
}
}
string s[100010];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
c['A']=0;c['G']=1;c['U']=2;c['C']=3;c['#']=4;
int q;
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>s[i];
s[i]=s[i]+"#"+s[i];//字符串映射
}
dfs(0);
for(int i=1;i<=q;i++){
string s,t;
cin>>s>>t;
s=t+"#"+s;//字符串映射
ins(s,i);
}
build();//建AC自动机
for(int i=1;i<=id;i++)G[fail[i]].push_back(i);
for(int i=1;i<=n;i++)query(s[i]);//多模匹配
dfs(0);
for(int i=1;i<=q;i++){
cout<<ed[ip[i]]<<'\n';
}
return 0;
}