Luogu4762 [CERC2014]Virus synthesis

Description

link

给定一个字符串,求通过以下两种方式最少用几次就可以构造出来它

\(1.\) 在当前串尾添加任意一个字符

\(2.\) 在串开头或末尾加一个当前的逆串

Solution

首先发现 \(2\) 操作就是可以把一个偶数长度的回文串通过较少次构造出来

对这个给定的串建 \(PAM\) 吧,顺便求一下 \(trans\) 指针

然后在 \(PAM\) 上面 \(dp\)

直接从偶根 \(bfs\) (像 \(AC\) 自动机构建 \(fail\) 指针一样)

\(f_i\) 为构造出来当前的串至少需要多少次操作

然后 \(ans=\min\limits _ {i=2} ^{tot} n-len_i+f_i\)

转移分为以下两种:

\(1.\) 当前串的长度\(len_i\)

\(2.\) 从自动机上面直接转移 \(f_i=min(f_i,f_{fail_i}+1)\)

\(3.\)\(trans\) 指针上面转移

\[f_i=min(f_i,f_{trans_i} +1 +\frac {len_i}{2}-len_{trans_i}) \]

(补齐前缀然后复制)

一坑点:\(ans\) 记得初始最大值设成 \(n\)

Code

#include<bits/stdc++.h>
using namespace std;
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=1e5+10;
	int ans;
	struct PAM{
		int t[N],fail[N],ch[N][4],tot,las,n,len[N],f[N];
		char s[N];
		inline void init()
		{			
			for(int i=0,j;i<=tot;++i) 
			{
				for(j=0;j<4;++j) ch[i][j]=0;
				t[i]=0; f[i]=0; fail[i]=0; len[i]=0;
			}
			ans=2e9+10; fail[0]=fail[1]=tot=1; len[1]=-1; las=0;
			return ;
		}
		inline void extend(int i)
		{
			int c=s[i]-'A',p=las;
			while(s[i-len[p]-1]!=s[i]) p=fail[p];
			if(ch[p][c]) return las=ch[p][c],void();
			int y=++tot,x=fail[p];
			while(s[i-len[x]-1]!=s[i]) x=fail[x];
			len[y]=len[p]+2; fail[y]=ch[x][c]; las=ch[p][c]=y; 
			if(len[y]<=2) return t[y]=fail[y],void();
			int q=t[p]; while(len[q]*2+4>len[y]||s[i-len[q]-1]!=s[i]) q=fail[q];
			t[y]=ch[q][c];
			return ;
		}
		inline void work()
		{
			queue<int> q; for(int i=2;i<=tot;++i) f[i]=len[i];
			for(int i=0;i<4;++i) if(ch[0][i]) q.push(ch[0][i]);
			while(!q.empty())
			{
				int fr=q.front(); q.pop();
				f[fr]=min(f[fr],f[t[fr]]+1+len[fr]/2-len[t[fr]]);
				ans=min(ans,n-len[fr]+f[fr]); 
				for(int i=0;i<4;++i)
				{
					if(!ch[fr][i]) continue;
					f[ch[fr][i]]=min(f[ch[fr][i]],f[fr]+1); q.push(ch[fr][i]);
				}
			} return ;
		}
	};
	PAM a;
	inline char c(char p)
	{
		if(p=='A') return 'A';
		if(p=='G') return 'B';
		if(p=='C') return 'C';
		if(p=='T') return 'D';
		else return 0;
	}
	inline void work()
	{
		scanf("%s",a.s+1); a.init(); a.s[0]='#';
		int len=strlen(a.s+1); a.n=len; 
		for(int i=1;i<=len;++i) a.s[i]=c(a.s[i]),a.extend(i);
		a.work(); ans=min(ans,len);
		printf("%d\n",ans); 
		return ;
	}
	signed main()
	{
		int T=read(); while(T--) work();
		return 0;
	}
}
signed main(){return yspm::main();} 
posted @ 2020-07-14 07:21  yspm  阅读(121)  评论(0编辑  收藏  举报