[bzoj2342][SHOI2011]双倍回文

2342: [Shoi2011]双倍回文

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1855 Solved: 691
[Submit][Status][Discuss]
Description

这里写图片描述

Input

输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容。

Output

输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文子串不存在,则输出0。

Sample Input

16

ggabaabaabaaball

Sample Output

12

HINT

N<=500000

先用 manacher 求出来以每个字母为中心的回文串的长度。
然后暴力枚举中心位置,用之前 manacher 处理的算出右端点最大在哪,然后从大往小枚举,遇到第一个符合的就停。
虽然是暴力,但是跑的飞快。。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000010;
int n,p[N<<1];
char s[N],ch[N];
inline void manacher(){
    int maxn=1,id=1,i;
    for(ch[0]='$',ch[1]='#',i=1;i<=n;++i)
        ch[i<<1]=s[i-1],ch[i<<1|1]='#';
    for(i=1;i<=(n<<1|1);++i){
        p[i]=min(maxn-i,p[id*2-i]);
        while(ch[i+p[i]]==ch[i-p[i]]) ++p[i];
        if(maxn<p[i]+i) maxn=p[i]+i,id=i;
    }
}
int main(){
    int i,ans=0;
    scanf("%d%s",&n,s);
    manacher();
    for(i=1;i<=(n<<1|1);i+=2){
        int now=p[i],o=i+p[i]-1;
        if(ans>=o-i) continue;
        while(o>=i){
            if(((o-i)/2)%2==0){
                int oo=(o+i)/2;
                if(p[oo]+oo-1>=o){
                    ans=max(ans,o-i);
                    break;
                }
            }
            o-=2;
        }
    }
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值