zoukankan      html  css  js  c++  java
  • P4762 [CERC2014]Virus synthesis

    感觉这道题目有点意思,希望他不会被我一眼秒了。

    好像有一个有点正确(?)的嘴巴,找出最大的偶回文串,然后这个是可以通过操作二减少步骤的。

    然后考虑最大的偶回文串一定不能向外执行操作二了?好像是的。

    这样我们就转换成了子问题,如何快速求出最大偶回文串的一半的长度。

    发现每一次长度必然减半,所以最多只会执行 (log_2n) 次,所以直接考虑每次用 (PAM) 或马拉车求一下就行了。

    等等我发现一个巨大问题,这个子问题转换一定最优吗?

    如果碰到了相同大小的回文子串该怎么办呢?

    可能当前决策是最优的但是不满足全局最优啊。。。

    咦等下,我们考虑本质不同的回文子串的个数是只有 (O(n))​ 个的,所以说我们能否把所有的子串的答案求出来?

    哦,我们考虑在回文树上一个子串如果是另一个子串的回文后缀,那么其一半也必然满足后缀关系。

    我们可以考虑从回文树的顶端向下遍历,考虑往前加字符,然后求出该一半的对应值,这个应该是在后缀树上 (dp) ,我们需要类似树剖倍增和线段树的东西来搞就行了。然后再多考虑一个转移即可。

    发现还是过不了样例,自闭了,但是感觉方法没错,我不想调了。


    发现你根本不用考虑奇串,考虑回文串的性质,更优的偶串会在前面就更新。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int n;char s[N];
    int trans(char c){
    	if(c=='A') return 0;
    	if(c=='T') return 1;
    	if(c=='G') return 2;
    	return 3;
    }
    char trans(int x){
    	if(x==0) return 'A';
    	if(x==1) return 'T';
    	if(x==2) return 'G';
    	return 'C';
    }
    struct PAM{
    	int rt0,rt1,len,lst,tot;
    	struct Node{int fail,len,go[4];}tr[N];
    	PAM(){rt0=1,init();}
    	void init(){
    		for(int i=0;i<=tot;++i) tr[i]=Node();
    		lst=len=0,tot=1,tr[rt1].len=-1,tr[rt0].fail=rt1;
    	}
    	int find(int u,char c){
    		while(s[len-tr[u].len-1]!=c) u=tr[u].fail;
    		return u;
    	}
    	void insert(char c){
    		int u=lst;len++;u=find(u,c);
    		if(!tr[u].go[trans(c)]){
    			tr[u].go[trans(c)]=++tot,tr[tot].len=tr[u].len+2;
    			if(tr[tot].len==1) tr[tot].fail=rt0;
    			else tr[tot].fail=tr[find(tr[u].fail,c)].go[trans(c)];
    		}
    		lst=tr[u].go[trans(c)];
    	}
    }pam;
    struct Tree{
    	int n;
    	struct Edge{int nxt,to;}e[N];int fir[N];
    	void add(int u,int v,int i){e[i]=(Edge){fir[u],v},fir[u]=i;}
    	struct Node{int len,f,fa,deg,fail[20],go[4];}tr[N];
    	void init(){
    		for(int i=1;i<=n;++i) fir[i]=0,tr[i]=Node();
    	}
    	void fuck(){
    		for(int j=1;j<20;++j){
    			for(int i=1;i<=n;++i)
    			tr[i].fail[j]=tr[tr[i].fail[j-1]].fail[j-1];
    		}
    	}
    	void dp(){
    		queue<int> q;
    		for(int i=1;i<=n;++i) if(!tr[i].deg) q.push(i);
    		while(!q.empty()){
    			int u=q.front();q.pop();
    			if(tr[u].len&1) tr[u].f=tr[u].len;
    			else{
    				int v=u;
    				for(int i=19;i>=0;--i){
    					if(tr[tr[v].fail[i]].len>tr[u].len/2)
    					v=tr[v].fail[i];
    				}
    				v=tr[v].fail[0];
    				tr[u].f=min(tr[v].f+tr[u].len/2-tr[v].len+1,tr[tr[u].fa].f+1);
    			}
    			for(int i=fir[u];i;i=e[i].nxt){
    				int v=e[i].to;tr[v].deg--;
    				if(!tr[v].deg) q.push(v);
    			}
    			for(int i=0;i<4;++i){
    				if(!tr[u].go[i]) continue;
    				tr[tr[u].go[i]].deg--;
    				if(!tr[tr[u].go[i]].deg)
    					q.push(tr[u].go[i]);
    			}
    		}
    	}
    }t;
    int solve(){
    	scanf("%s",s+1),n=strlen(s+1);
    	pam.init(),t.init();
    	for(int i=1;i<=n;++i) pam.insert(s[i]);
    	t.n=pam.tot;
    	for(int i=1;i<=t.n;++i){
    		t.tr[i].deg++;
    		t.tr[i].len=pam.tr[i].len;
    		t.tr[i].fail[0]=pam.tr[i].fail;
    		t.add(t.tr[i].fail[0],i,i);
    		for(int j=0;j<4;++j)
    			t.tr[i].go[j]=pam.tr[i].go[j];
    		for(int j=0;j<4;++j){
    			if(!pam.tr[i].go[j]) continue;
    			t.tr[pam.tr[i].go[j]].fa=i;
    			t.tr[pam.tr[i].go[j]].deg++;
    		}
    	}
    	t.tr[1].deg--,t.fuck(),t.dp();
    	int res=1e9+7;
    	for(int i=1;i<=t.n;++i)
    		res=min(res,t.tr[i].f+n-t.tr[i].len);
    	return printf("%d
    ",res),0;
    }
    int main(){
    	int T;cin>>T;
    	while(T--) solve();
    	return 0;
    }
    
  • 相关阅读:
    leetcode108 Convert Sorted Array to Binary Search Tree
    leetcode98 Validate Binary Search Tree
    leetcode103 Binary Tree Zigzag Level Order Traversal
    leetcode116 Populating Next Right Pointers in Each Node
    Python全栈之路Day15
    Python全栈之路Day11
    集群监控
    Python全栈之路Day10
    自动部署反向代理、web、nfs
    5.Scss的插值
  • 原文地址:https://www.cnblogs.com/Point-King/p/15123898.html
Copyright © 2011-2022 走看看