zoukankan      html  css  js  c++  java
  • Codechef Palindromeness 和 SHOI2011 双倍回文

    Palindromeness

    Let us define the palindromeness of a string in the following way:

    • If the string is not a palindrome, its' palindromeness is zero.
    • The palindromeness of an one-letter string is 1.
    • The palindromness of a string S of the length greater than one is 1 + "palindromeness of the string that is formed by the first [|S|/2] symbols of S".

    You are given a string S. Find the sum of the palindromenesses of all the non empty substrings of S (i.e. S[i..j], where i <= j). In other words, you have to calculate the sum of palindromenesses of N * (N + 1) / 2 substrings of S, where N is the length of S.

    • 1|S|105

    题解

    翁文涛《回文树及其应用》。

    solution

    (len_i=1) 时特殊处理 (half_i=even)

    CO int N=100000+10;
    
    namespace PAM{
    	int str[N],n;
    	int last,tot;
    	int ch[N][26],fa[N],len[N];
    	int half[N],val[N],siz[N];
    	
    	void init(){
    		memset(str,-1,sizeof str),n=0;
    		last=tot=1;
    		memset(ch,0,sizeof ch);
    		fa[0]=fa[1]=1,len[0]=0,len[1]=-1;
    		memset(siz,0,sizeof siz);
    	}
    	int get_fail(int x){
    		while(str[n-len[x]-1]!=str[n]) x=fa[x];
    		return x;
    	}
    	void extend(int c){
    		int p=get_fail(last);
    		if(!ch[p][c]){
    			int cur=++tot;
    			len[cur]=len[p]+2;
    			fa[cur]=ch[get_fail(fa[p])][c];
    			ch[p][c]=cur;
    			if(len[cur]==1) half[cur]=0;
    			else{
    				int q=half[p];
    				while(str[n-len[q]-1]!=str[n] or
    					  2*(len[q]+2)>len[cur]) q=fa[q];
    				half[cur]=ch[q][c];
    			}
    			val[cur]=1+(len[cur]/2==len[half[cur]]?val[half[cur]]:0);
    		}
    		last=ch[p][c];
    		++siz[last];
    	}
    	LL main(){
    		for(int i=tot;i>=2;--i) siz[fa[i]]+=siz[i];
    		LL ans=0;
    		for(int i=tot;i>=2;--i) ans+=(LL)siz[i]*val[i];
    		return ans;
    	}
    }
    
    char str[N];
    
    void real_main(){
    	scanf("%s",str+1);
    	int n=strlen(str+1);
    	PAM::init();
    	for(int i=1;i<=n;++i){
    		PAM::str[++PAM::n]=str[i]-'a';
    		PAM::extend(str[i]-'a');
    	}
    	printf("%lld
    ",PAM::main());
    }
    int main(){
    	for(int T=read<int>();T--;) real_main();
    	return 0;
    }
    

    双倍回文

    如果 s 能够写成 wwRwwR 的形式,则称 s 是双倍回文。

    s 的长度是 4 的倍数,前后两半都是相同的回文。

    对于给定的字符串,计算它的最长双倍回文串的长度。

    N<=500000

    yyb的题解

    发现这个长度为自身一半的的回文串是可以方便地转移的。

    对于每个节点,我们维护一个half来表示长度最长的、不超过它长度一半的那个祖先节点

    这样子只需要判断一下当前点的half长度是否是一半,并且当前串的长度是四的倍数就好了

    找 half 就用 p 的 half 来跳就行了。

    co int N=500000+10;
    char s[N];
    int last=1,tot=1;
    int ch[N][26],fa[N]={1,1},len[N]={0,-1},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][s[i]-'a'];
    	if(!x){
    		x=++tot;
    		fa[x]=ch[get_fa(fa[p],i)][s[i]-'a'];
    		len[x]=len[p]+2;
    		ch[p][s[i]-'a']=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][s[i]-'a'];
    		}
    	}
    	last=x;
    }
    int main(){
    	int n=read<int>();
    	scanf("%s",s+1);
    	for(int i=1;i<=n;++i) extend(i);
    	int ans=0;
    	for(int i=1;i<=tot;++i)
    		if(len[half[i]]<<1==len[i]&&len[i]%4==0)
    			ans=max(ans,len[i]);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    二读《活着》有感
    Linux系统上安装JDK和Tomcat服务器
    在阿里云服务器上安装完成并启动Tomcat后,通过http不能访问--解决办法
    安装JDK出现错误:-bash: /usr/java/jdk1.7.0_71/bin/java: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory解决办法
    python结巴(jieba)分词
    mysql数据库优化
    ansible常见模块
    CentOS6.5 64位下安装部署Ansible
    [Python] 利用commands模块执行Linux shell命令
    python迭代器
  • 原文地址:https://www.cnblogs.com/autoint/p/11419611.html
Copyright © 2011-2022 走看看