zoukankan      html  css  js  c++  java
  • 【洛谷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;
    }
    
  • 相关阅读:
    打造自定义 eslint
    二叉树(三): 二叉查找树
    二叉树(二): 补充
    二叉树(一): 遍历
    redux 源码浅析
    react-redux 源码浅析
    WebComponents使用以及思考
    SHELL 语法以及实例
    React-Native 原生 APP 更新
    关于 cdn 在项目中的使用
  • 原文地址:https://www.cnblogs.com/stoorz/p/14265991.html
Copyright © 2011-2022 走看看