• 【洛谷P4762】Virus synthesis


    题目

    题目链接:https://www.luogu.com.cn/problem/P4762
    初始有一个空串,利用下面的操作构造给定串 (S)

    1. 串开头或末尾加一个字符。
    2. 串开头或末尾加一个该串的逆串。

    求最小化操作数,(|S| leq 10^5)

    思路

    考虑在 PAM 上 dp。一个节点 (x) 可以被转移的方案只有以下三种:

    1. 全部采用操作 (1),操作次数为 (mathrm{len}_x)
    2. 从其父亲节点转移而来,可以在父节点准备进行操作二之前再加入一个字符,然后再操作二。操作次数为 (f_{fa}+1)
    3. 从其某一个长度不超过一般的后缀回文串再加若干个字符,然后再进行操作二。不难发现这个后缀回文串一定是其最长的且长度不超过其长度一般的后缀回文串。操作次数为 (f_{y}+mathrm{frac{mathrm{len}_x}{2}-mathrm{len}_y}+1)

    然后取最优答案即可。
    时间复杂度 (O(n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=100010,Inf=1e9;
    int Q,n,ans,f[N];
    char s[N];
    
    int ID(char c)
    {
    	if (c=='A') return 0;
    	if (c=='C') return 1;
    	if (c=='G') return 2;
    	if (c=='T') return 3;
    }
    
    struct PAM
    {
    	int last,tot,fail[N][2],ch[N][4],len[N];
    	
    	void build()
    	{
    		for (int i=0;i<=tot;i++)
    			fail[i][0]=fail[i][1]=len[i]=ch[i][0]=ch[i][1]=ch[i][2]=ch[i][3]=0;
    		last=0; tot=1; fail[0][0]=1; len[1]=-1;
    		f[0]=1; f[1]=0;
    	}
    	
    	int getfail(int m,int x)
    	{
    		while (s[m]!=s[m-len[x]-1]) x=fail[x][0];
    		return x;
    	}
    	
    	void ins(int m,int c)
    	{
    		int p=getfail(m,last);
    		if (!ch[p][c])
    		{
    			int np=++tot;
    			len[np]=len[p]+2; f[np]=len[np];
    			fail[np][0]=fail[np][1]=ch[getfail(m,fail[p][0])][c];
    			if (len[np]>2)
    			{
    				f[np]=len[np];
    				int q=fail[p][1];
    				while (s[m]!=s[m-len[q]-1] || len[ch[q][c]]*2>len[np]) q=fail[q][0];
    				if (!(len[np]&1)) f[np]=min(f[p]+1,f[ch[q][c]]+len[np]/2-len[ch[q][c]]+1);
    				fail[np][1]=ch[q][c];
    			}
    			ch[p][c]=np;
    			ans=min(ans,n-len[np]+f[np]);
    		}
    		last=ch[p][c];
    	}
    }pam;
    
    void prework()
    {
    	for (int i=0;i<=n;i++) f[i]=Inf;
    	pam.build(); ans=Inf;
    }
    
    int main()
    {
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		scanf("%s",s+1);
    		n=strlen(s+1);
    		prework();
    		for (int i=1;i<=n;i++)
    			pam.ins(i,ID(s[i]));
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    linux一切皆文件之tcp socket描述符(三)
    linux一切皆文件之Unix domain socket描述符(二)
    linux一切皆文件之文件描述符(一)
    k8s之使用secret获取私有仓库镜像
    https、ssl、tls协议学习
    k8s网络之calico学习
    泛型的原理、应用、约束、缓存
    C#中Unity对象的注册方式与生命周期解析
    监听EF执行的sql语句及状态
    递归一个List<T>,可自己根据需要改造为通用型。
  • 原文地址:https://www.cnblogs.com/stoorz/p/14265991.html
Copyright © 2020-2023  润新知