AC自动机模板题
P3808 AC自动机(简单版)
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
#include<bits/stdc++.h>
using namespace std;
const int maxx = 1e6+10;
int trie[maxx][26],tot;
int sum[maxx],fail[maxx];
void Insert(string s)
{
int rt=0;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
if(!trie[rt][id])trie[rt][id]=++tot;
rt=trie[rt][id];
}
sum[rt]++;
}
void get_fail()
{
queue<int>q;
for(int i=0;i<26;i++)
if(trie[0][i])fail[trie[0][i]]=0,q.push(trie[0][i]);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=0;i<26;i++)
{
if(trie[u][i])fail[trie[u][i]]=trie[fail[u]][i],q.push(trie[u][i]);
else trie[u][i]=trie[fail[u]][i];
}
}
}
int query(string s)
{
int rt=0,ans=0;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
rt=trie[rt][id];
for(int k=rt;k&&sum[k]!=-1;k=fail[k])
ans+=sum[k],sum[k]=-1;
}
return ans;
}
int main()
{
int n;
scanf("%d",&n);
string s;
for(int i=1;i<=n;i++)
cin>>s,Insert(s);
get_fail();
cin>>s;
printf("%d\n",query(s));
return 0;
}
P3796 AC自动机(加强版)
有N个由小写字母组成的模式串以及一个文本串T。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串T中出现的次数最多。
#include<bits/stdc++.h>
using namespace std;
const int maxx = 2e4+10;
int trie[maxx][26],tot;
int sum[maxx],fail[maxx];
int ans[maxx];
string s[maxx];
void Insert(string s,int x)
{
int rt=0;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
if(!trie[rt][id])trie[rt][id]=++tot;
rt=trie[rt][id];
}
sum[rt]=x;
}
void get_fail()
{
queue<int>q;
for(int i=0;i<26;i++)
if(trie[0][i])fail[trie[0][i]]=0,q.push(trie[0][i]);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=0;i<26;i++)
{
if(trie[u][i])fail[trie[u][i]]=trie[fail[u]][i],q.push(trie[u][i]);
else trie[u][i]=trie[fail[u]][i];
}
}
}
void query(string s)
{
int rt=0;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
rt=trie[rt][id];
for(int k=rt;k;k=fail[k])ans[sum[k]]++;
}
}
int main()
{
int n;
while(~scanf("%d",&n)&&n)
{
tot=0;
memset(trie,0,sizeof(trie));
memset(sum,0,sizeof(sum));
memset(fail,0,sizeof(fail));
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++)
cin>>s[i],Insert(s[i],i);
get_fail();
string t;
cin>>t;
query(t);
int tmp=0;
for(int i=1;i<=n;i++)tmp=max(tmp,ans[i]);
printf("%d\n",tmp);
for(int i=1;i<=n;i++)
if(ans[i]==tmp)cout<<s[i]<<endl;
}
return 0;
}
P5357 AC自动机(二次加强版)
给你一个文本串 S 和 n 个模式串 T1...Tn,请你分别求出每个模式串Ti 在 S 中出现的次数。
拓扑建图优化
#include<bits/stdc++.h>
using namespace std;
const int maxx = 2e5+10;
int trie[maxx][26],tot;
int fail[maxx],vis[maxx];
int in[maxx],ma[maxx],sum[maxx],ans[maxx];
void Insert(string s,int x)
{
int rt=0;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
if(!trie[rt][id])trie[rt][id]=++tot;
rt=trie[rt][id];
}
if(!vis[rt])vis[rt]=x;
ma[x]=vis[rt]; //重复单词
}
void getfail()
{
queue<int>q;
for(int i=0;i<26;i++)
if(trie[0][i])fail[trie[0][i]]=0,q.push(trie[0][i]);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=0;i<26;i++)
{
if(trie[u][i])
{
fail[trie[u][i]]=trie[fail[u]][i];
in[fail[trie[u][i]]]++;
q.push(trie[u][i]);
}
else trie[u][i]=trie[fail[u]][i];
}
}
}
void query(string s)
{
int rt=0;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
rt=trie[rt][id];
sum[rt]++;
}
}
void topu()
{
queue<int>q;
for(int i=0;i<=tot;i++)
if(in[i]==0)q.push(i);
while(!q.empty())
{
int u=q.front();q.pop();
ans[vis[u]]=sum[u];
int v=fail[u];
in[v]--;
sum[v]+=sum[u];
if(in[v]==0)q.push(v);
}
}
int main()
{
int n;
scanf("%d",&n);
string s;
for(int i=1;i<=n;i++)
cin>>s,Insert(s,i);
getfail();
cin>>s;
query(s);
topu();
for(int i=1;i<=n;i++)
printf("%d\n",ans[ma[i]]);
return 0;
}