【AC自动机】【例题】AC自动机

洛谷P3796

题目:

都说了是AC自动机模板。。。

题解:

get_fail每次都很恼火
因为优化很多,但隔这么久,第二次看还是更懂一点了
下一次应该就把板子定了吧。。。

#include
#define x s[i]-'a'
using namespace std;
const int N=1e6+10;
int T;
int n;
int ans[155];
int t[60005][30],tot;
int g[60005];
int bl[60005];
int f[60005];
void init()
{
	memset(t,0,sizeof(t));
	memset(g,0,sizeof(g));
	memset(bl,0,sizeof(bl));
	memset(f,0,sizeof(f));tot=0;
	memset(ans,0,sizeof(ans));
}
void add(char s[],int i)
{
	int p=0;
	for(int i=0;s[i];i++)
	{
		if(!t[p][x])t[p][x]=++tot;
		p=t[p][x];
	}g[p]++;bl[p]=i;
}
void get_fail()
{
	queue<int>q;
	int p=0;
	for(int i=0;i<26;i++)
		if(t[p][i])q.push(t[p][i]);
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=0;i<26;i++)
		{
			int v=t[u][i],as=f[u];
			if(v)
			{
				while(as&&!t[as][i])as=f[as];
				//没有这个点,就失败,跳fail指针
				f[v]=t[as][i];
				q.push(v);
			}
			else t[u][i]=t[as][i];
			//很迷的东西对吧,实际上是优化
			//下面没有节点了,就把fail指针的节点变为当前子节点,反正都是要走到这的
			//虽然原trie树改了,但改了计算时没有影响正确性
		}
	}
}
void find(char s[])
{
	int p=0;
	for(int i=0;s[i];i++)
	{
		p=t[p][x];
		for(int j=p;j;j=f[j])ans[bl[j]]++;
		//统计
	}
}
char s[155][102];
char tt[N];
int main()
{
	while(scanf("%d",&n)&&n)
	{
		init();
		for(int i=1;i<=n;i++)
		{
			scanf("%s",s[i]);
			add(s[i],i);
		}
		get_fail();
		scanf("%s",tt);
		find(tt);
		int maxx=0;
		for(int i=1;i<=n;i++)maxx=max(maxx,ans[i]);printf("%d\n",maxx);
		for(int i=1;i<=n;i++)if(maxx==ans[i])printf("%s\n",s[i]);
	}
}

加强版
新晋毒瘤模板!

#include
using namespace std;
const int N=2e6+10;
int t[N][30],all;
int f[N],las[N];
int val[N],sam[N];
void putin(char *s,int bt)
{
	int p=0;
	for(int i=0;s[i];i++)
	{
		int now=s[i]-'a';
		if(!t[p][now])t[p][now]=++all;
		p=t[p][now];
	}
	if(!val[p])val[p]=bt;
	else sam[bt]=val[p];
}
void get_fail()
{
	queue<int>q;
	int p=0;
	for(int i=0;i<26;i++)
	if(t[p][i])q.push(t[p][i]);
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=0;i<26;i++)
		{
			p=t[u][i];
			if(!p)
			{
				t[u][i]=t[f[u]][i];
				continue;
			}
			q.push(p);
			int pre=f[u];
			while(pre&&!t[pre][i])pre=f[pre];
			f[p]=t[pre][i];
			las[p]=val[f[p]]?f[p]:las[f[p]];
		}
	}
}
int ans[N];
void work(char *s)
{
	int p=0;
	for(int i=0;s[i];i++)
	{
		int now=s[i]-'a';
		p=t[p][now];
		int pre=0;
		pre=val[p]?p:las[p];
		while(pre)
		{
			ans[val[pre]]++;
			pre=las[pre];
		}
	}
}
int n;
char s[N];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s);
		putin(s,i);
	}
	get_fail();
	scanf("%s",s);
	work(s);
	for(int i=1;i<=n;i++)
	{
		if(sam[i])printf("%d\n",ans[sam[i]]);
		else	  printf("%d\n",ans[i]);
	}
}

你可能感兴趣的:(#,AC)