1. 程式人生 > >[bzoj2342][SHOI2011]雙倍迴文

[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); }