码迷,mamicode.com
首页 > 其他好文 > 详细

P4555 [国家集训队]最长双回文串

时间:2018-09-28 12:32:22      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:manacher   turn   algorithm   bsp   etc   pac   ios   i++   show   

传送门

搞回文串很容易想到manacher

把每个回文串看成线段

那就是求两个相邻线段的最长总长度

设 l[ i ] 表示左端点为 i-1 时线段的最大长度,r[ i ] 表示右端点为 i+1 时线段的最大长度

(这里 i 在manacher处理后的字符串a上,线段的最大长度是指原字符串上的长度)

那么ans=max(ans, l[ i ] + r[ i ] ) (a[ i ] == ‘ # ‘)

当 i 刚好为长线段的端点时的 l[ i ] 和 r[ i ] 在manacher 时可以处理好

当 i 在长线段的内部时 l[ i ] 和 r[ i ] 可以递推出来

l [ i ] =max(l[ i ],l[ i-2 ] -2) (i-2是因为 i 在a上,l[ i-2 ] - 2 是因为要保持回文,左右两边都要去掉)

r [ i ] 也差不多处理

具体看代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1e7+7;
char s[N],a[N];
int f[N],l[N],r[N],ans,len;
inline void read_s()
{
    char ch=getchar();
    while(ch<a||ch>z) ch=getchar();
    while(ch>=a&&ch<=z) s[++len]=ch,ch=getchar();
}
int main()
{
    read_s();
    len=len*2+1;
    for(int i=1;i<=len;i++)
        a[i]= i&1 ? # : s[i>>1];
    a[0]=$;
    int pos=0,mx=0;
    for(int i=1;i<=len;i++)
    {
        f[i]= i>=mx ? 1 : min(f[pos*2-i],mx-i);
        while(a[i+f[i]]==a[i-f[i]]) f[i]++;
        if(i+f[i]>mx) mx=i+f[i],pos=i;
        l[i-f[i]+1]=max(l[i-f[i]+1],f[i]-1);
        r[i+f[i]-1]=max(r[i+f[i]-1],f[i]-1);
    }
    for(int i=3;i<len;i+=2) l[i]=max(l[i],l[i-2]-2);//只要计算‘#‘的l,r数组
    for(int i=len-2;i>=3;i-=2) r[i]=max(r[i],r[i+2]-2);
    for(int i=3;i<len;i+=2) ans=max(ans,l[i]+r[i]);//主要i!=1&&i!=len,题目要求线段长度不能为0
    printf("%d",ans);
    return 0;
}

 

P4555 [国家集训队]最长双回文串

标签:manacher   turn   algorithm   bsp   etc   pac   ios   i++   show   

原文地址:https://www.cnblogs.com/LLTYYC/p/9717299.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!