• LG4762 Virus synthesis


    Virus synthesis

    初始有一个空串,利用下面的操作构造给定串 S 。

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

    求最小化操作数, ∣S∣≤105

    题解

    显然应该多使用操作2——翻转复制。

    建出 S 的回文自动机,设 dp(i) 表示构造节点 i 表示回文串所需最少操作次数。

    ans=min {dp(i)+n-leni}

    若 i 能转移到 j,则 dp(j)=dp(i)+1。因为 i 是回文串,所以 i 一定是由翻转复制得到的。在这之前一步加上 j 的字符就是这个转移的意义。

    回文自动机维护出 half,那么 dp(i)=dp(halfi)+leni/2-lenhalfi+1。这个转移意义很明显。

    发现转移需要回文自动机的 DAG 的更新顺序,所以使用队列维护。

    时间复杂度 (O(|S|))

    co int N=100000+10;
    char s[N];
    il int idx(char c){
    	switch(c){
    		case 'A':return 0;
    		case 'G':return 1;
    		case 'C':return 2;
    		default:return 3;
    	}
    }
    
    int last,tot;
    int ch[N][4],fa[N],len[N],half[N];
    
    int get_fa(int x,int i){
    	while(s[i-len[x]-1]!=s[i]) x=fa[x];
    	return x;
    }
    void extend(int i){
    	int p=get_fa(last,i);
    	int x=ch[p][idx(s[i])];
    	if(!x){
    		x=++tot,memset(ch[x],0,sizeof ch[x]);
    		fa[x]=ch[get_fa(fa[p],i)][idx(s[i])];
    		len[x]=len[p]+2;
    		ch[p][idx(s[i])]=x;
    		if(len[x]==1) half[x]=0;
    		else{
    			int q=half[p];
    			while(s[i-len[q]-1]!=s[i]||(len[q]+2)<<1>len[x]) q=fa[q];
    			half[x]=ch[q][idx(s[i])];
    		}
    	}
    	last=x;
    }
    
    int dp[N];
    void real_main(){
    	last=tot=1;
    	memset(ch[0],0,sizeof ch[0]),memset(ch[1],0,sizeof ch[1]);
    	fa[0]=fa[1]=1,len[1]=-1;
    	
    	scanf("%s",s+1);int n=strlen(s+1);
    	for(int i=1;i<=n;++i) extend(i);
    	
    	dp[0]=1; // ""->"a,a" : cost=2
    	for(int i=2;i<=tot;++i) dp[i]=len[i];
    	deque<int> q(1,0);
    	int ans=n;
    	while(q.size()){
    		int p=q.front();q.pop_front();
    		for(int c=0;c<4;++c){
    			int x=ch[p][c];
    			if(!x) continue;
    			dp[x]=dp[p]+1;
    			int y=half[x];
    			dp[x]=min(dp[x],dp[y]+(len[x]>>1)-len[y]+1);
    			ans=min(ans,dp[x]+n-len[x]);
    			q.push_back(x);
    		}
    	}
    	printf("%d
    ",ans);
    }
    int main(){
    	for(int T=read<int>();T--;) real_main();
    	return 0;
    }
    
  • 相关阅读:
    win_tc使用感受
    10进制转8进制(栈操作)
    动态栈
    数组
    单链表学习
    static用法
    基础2
    linux c first
    linux net command /uboot command
    opencv
  • 原文地址:https://www.cnblogs.com/autoint/p/11420516.html
Copyright © 2020-2023  润新知