zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    类与类之间的几种关系
    spring之BeanFactory
    java打开本地应用程序
    java笔记六:线程间的协调
    继承与组合的优缺点
    适配器模式之对象适配器
    java笔记三:List接口
    java笔记二:final关键字用法总结
    设计模式之命令模式
    利用栈实现迷宫的求解
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/13295881.html
Copyright © 2011-2022 走看看