bzoj 4044: [Cerc2014] Virus synthesis【回文自动机+dp】

建回文自动机,注意到一个回文串是可以通过一个长度小于等于这个串长度的一半的回文串添上一些字符然后复制得到的,也就是在自动机上向fa走,相当于treedp
每次都走显然会T,记录一个up,指向祖先中最下长度符合要求的回文后缀,这样每次找最多跳一次,所以是O(n)的,还有child的清空动态的做,也就是新建一个点清空一个点

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100005;
int T,n,ch[N][5],fa[N],up[N],dis[N],f[N],con,la,mp[205],ans;
char s[N];
void clr(int x)
{
	ch[x][0]=ch[x][1]=ch[x][2]=ch[x][3]=0;
}
void ins(int c,int w)
{
	int p=la;
	for(;s[w-1-dis[p]]!=s[w];p=fa[p]);
    if(!ch[p][c])
    {
        int cur=++con,q=fa[p]; 
		dis[cur]=f[cur]=dis[p]+2,clr(cur);
		for(;s[w-dis[q]-1]!=s[w];q=fa[q]);
        fa[cur]=ch[q][c];
        if(dis[cur]<=2) 
			up[cur]=fa[cur];
        else 
		{
			q=up[p]; 
			for(;s[w-dis[q]-1]!=s[w]||2*(dis[q]+2)>dis[cur];q=fa[q]); 
			up[cur]=ch[q][c];
		}
        ch[p][c]=cur;
        if((dis[cur]&1)==0) 
		{
			f[cur]=min(f[cur],f[up[cur]]+(dis[cur]/2-dis[up[cur]])+1); 
			if(p>=2) 
				f[cur]=min(f[cur],f[p]+1);
		}
        else 
			f[cur]=min(f[cur],min(dis[cur]-dis[fa[cur]]+f[fa[cur]],f[p]+2));
    }
    la=ch[p][c];
}
int main()
{
	scanf("%d",&T);
	mp['A']=0,mp['T']=1,mp['G']=2,mp['C']=3;
	while(T--)
	{
		scanf("%s",s+1);
		n=strlen(s+1);
		ans=n,con=1,la=0,dis[0]=0,dis[1]=-1,fa[0]=1,s[0]=-1;
		clr(0),clr(1);
		for(int i=1;i<=n;i++)
			ins(mp[s[i]],i);
        for(int i=2;i<=con;i++) 
			ans=min(ans,n-dis[i]+f[i]);
		printf("%d
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lokiii/p/10014574.html