• P4762 [CERC2014]Virus synthesis


    题意

    真是道回文自动机好题。

    首先考虑答案必定是一个回文串+剩余部分的形式,因此可以建出回文自动机,之后考虑每个长度为偶数的回文串。

    对于一个长度为偶数的回文串,设它在回文自动机上对应的节点为(x),我们对于每个(x)求出(trans_x)表示x的最长后缀回文串,满足(len_{trans_x}leqslant len_x/2)

    之后设(f_x)表示(x)拼成(x)这个串的最小代价,我们从(0)(偶根)出发进行(bfs),中途计算(f_x)

    对于(f_x)
    初值肯定是自身长度(f_x=len_x)
    如果存在一条边((x,y)),那么(f_y=f_x+1),因为我们可以在拼(x)时还没进行(2)操作时向(x)后面填一个字符,使其进行(2)操作后变为(y)
    同时(f_x=min(f_x,f_{trans_x}+1+lem_x/2-len_{trans_x})),即我们可以从(trans_x)变过来。

    对于每个(x),它对答案的贡献是(n-len_x+f_x)(n)是字符串长度。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    const int inf=1e9;
    int T,n,tot,last,ans;
    int fail[maxn],len[maxn],trans[maxn],f[maxn];
    int ch[maxn][5];
    char s[maxn];
    inline int change(char c)
    {
    	if(c=='A')return 1;
    	if(c=='G')return 2;
    	if(c=='C')return 3;
    	if(c=='T')return 4;
    	return 2333;
    }
    inline void init()
    {
    	for(int i=0;i<=tot;i++)
    		for(int j=1;j<=4;j++)
    			ch[i][j]=0;
    	fail[0]=1;len[1]=-1;
    	tot=1;last=0;
    }
    inline int getfail(int x,int pos)
    {
    	while(s[pos-len[x]-1]!=s[pos])x=fail[x];
    	return x;
    }
    inline void add(int c,int pos)
    {
    	int p=getfail(last,pos);
    	if(!ch[p][c])
    	{
    		int q=++tot,tmp;len[q]=len[p]+2;
    		tmp=getfail(fail[p],pos);
    		fail[q]=ch[tmp][c];ch[p][c]=q;
    		if(len[q]<=2)trans[q]=fail[q];
    		else  
    		{
    			tmp=trans[p];
    			while(s[pos-len[tmp]-1]!=s[pos]||((len[tmp]+2)<<1)>len[q])tmp=fail[tmp];
    			trans[q]=ch[tmp][c];
    		}
    	}
    	last=ch[p][c];
    }
    inline void solve()
    {
    	queue<int>q;
    	for(int i=2;i<=tot;i++)f[i]=len[i];
    	for(int i=1;i<=4;i++)if(ch[0][i])q.push(ch[0][i]);
    	while(!q.empty())
    	{
    		int x=q.front();q.pop();
    		f[x]=min(f[x],f[trans[x]]+1+len[x]/2-len[trans[x]]);
    		ans=min(ans,n-len[x]+f[x]);
    		for(int i=1;i<=4;i++)
    		{
    			if(!ch[x][i])continue;
    			int y=ch[x][i];
    			f[y]=min(f[y],f[x]+1);
    			q.push(y);
    		}
    	}
    }
    int main()
    {
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%s",s+1);n=strlen(s+1);
    		s[0]='#';
    		init();
    		for(int i=1;i<=n;i++)add(change(s[i]),i);
    		ans=n;solve();
    		printf("%d
    ",ans);
    	}
    	return 0;	
    }
    
  • 相关阅读:
    【Leetcode_easy】720. Longest Word in Dictionary
    【Leetcode_easy】717. 1-bit and 2-bit Characters
    【Leetcode_easy】709. To Lower Case
    【Leetcode_easy】707. Design Linked List
    【Leetcode_easy】706. Design HashMap
    第38课 栈和队列的相互转化
    第7章 网络层协议(4)_IGMP协议
    第7章 网络层协议(3)_ARP协议
    第33课 双向循环链表的实现
    第32课 Linux内核链表剖析
  • 原文地址:https://www.cnblogs.com/nofind/p/12070004.html
Copyright © 2020-2023  润新知