• P4555 最长双回文串


    https://www.luogu.com.cn/problem/P4555
    https://darkbzoj.tk/problem/2565

    (T=XY),其中 (X,Y) 均为回文串,求 (T) 的最大长度

    首先把每两个原有字符的间隙填充上其他字符,然后可以用 manacher 求出每个点的最大回文半径 (len_i),此时这个回文半径对应的回文串的实际长度是 (len_i-1)
    因为要求的是两个回文串拼起来,所以可以求 (l_i,r_i) 分表表示以 (i) 开头,结尾的回文串最大长度,答案就是 (max{l_i+r_i})

    当求出 (len_i) 时,这样更新:(l_{i-len_i+1}=max(l_{i-len_i+1},len_i-1),r_{i+len_i-1}=max(r_{i+len_i-1},len_i-1))
    注意这里 (l,r) 的下标是以填充后的字符串下标为准,而值是在原有字符串中的长度,也就是此时的 (len_i-1)
    而我们要考虑的也只是当 (s_i) 是填充进来的字符时,(l_i,r_i) 的值,因为此时他才满足向左向右都是原串的一个回文子串

    但,这样只是更新了最大长度,比如对于 (len_i'<len_i)(l_{i-len_i'+1}) 也可以用 (len_i'-1) 来更新,但这里并没有更新到
    所以做完 manacher 以后,还要分别对 (l,r) 处理:对于每一个填充进来的 (s_i)(l_i=max(l_i,l_{i-2}-2),r_i=max(r_i,r_{i+2}-2))
    也就是以 (i) 开头的,就考虑一下以 (i-2) 开头的(上一个填充进来的字符),用它的长度减去 (2)(减去一头一尾)来更新。以 (i) 结尾的也是同理

    最后考虑这些填充进来的 (s_i),取 (max{l_i+r_i}) 为答案

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    char in[100005],s[200005];
    int n;
    int len[200005];
    int l[200005],r[200005];
    int main(){
    	scanf("%s",in+1);
    	int lenin=std::strlen(in+1);
    	s[0]=0;s[1]=2;n=1;
    	for(reg int i=1;i<=lenin;i++) s[++n]=in[i],s[++n]=2;
    	s[n+1]=1;
    	int pos=0,max=0;
    	for(reg int i=1;i<=n;i++){
    		if(pos+max-1<i) len[i]=1;
    		else len[i]=std::min(len[pos+pos-i],pos+max-i);
    		while(s[i+len[i]]==s[i-len[i]]) len[i]++;
    		if(i+len[i]-1>=pos+max-1) pos=i,max=len[i];
    		l[i-len[i]+1]=std::max(l[i-len[i]+1],len[i]-1);
    		r[i+len[i]-1]=std::max(r[i+len[i]-1],len[i]-1);
    	}
    	for(reg int i=1;i<=n;i+=2) l[i]=std::max(l[i],l[i-2]-2);
    	for(reg int i=n;i>0;i-=2) r[i]=std::max(r[i],r[i+2]-2);
    	reg int ans=0;
    	for(reg int i=1;i<=n;i+=2) ans=std::max(ans,(l[i]&&r[i])*(l[i]+r[i]));
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    DOM getElementById
    百度之星2014
    游艇租借
    2014年acm亚洲区域赛·鞍山站
    UVALive 4255 Guess
    UVA 10054 The Necklace
    UVA 10047 The Monocycle
    UVA 11624 Fire!
    第九届黑龙江省赛
    剑指offer系列31-----二叉树的下一个节点
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/13295881.html
Copyright © 2020-2023  润新知