【Manacher】最長迴文子串

caioj任意門

hz2016評測傳送門

可以的話來一下hz2016評測吧,有的題caioj沒有的我也可以給到數據嘛。
#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Maxchar 100000
#define mes(x,y) memset(x,y,sizeof(x));
#define mpy(x,y) memcpy(x,y,sizeof(x))
#define INF 2147483647
using namespace std;
int p[2*Maxchar+1];
char s[2*Maxchar+1],now[2*Maxchar+1];
int Manacher(){
    int len=strlen(s+1);
    for(int i=1;i<=len;i++)now[2*i-1]='#',now[2*i]=s[i];
    len=len*2+1;
    now[len]='#';
    int pos=0,R=0;//R表示當前訪問到的所有迴文子串,所能觸及的最右一個字符的位置,pos表示R位置的迴文串的中心
    for(int i=1;i<=len;i++){
        int j=2*pos-i;//j爲i關於pos的對稱點 
        if(i<=R)p[i]=min(p[j],R-i);
		/*
		如果i<=R的話,分兩種情況
		第一種情況p[j]>R-i時,表示j對稱點的最長迴文子串已經越出R的界限了
			這時,因爲我們不確定大於R時的情況,所以p[i]暫時等於R-i
		第二種情況p[j]<=R-i時,那就可以直接繼承p[j]得p[i]=p[j]
		綜合以上兩種情況,我們可以用p[i]=min(p[j],R-i)來歸納
		*/
        else p[i]=1;//不然就要暴力枚舉
        while(1<=i-p[i]&&i+p[i]<=len&&now[i-p[i]]==now[i+p[i]])p[i]++;
		//向左右枚舉,更新p[i],即是作爲繼承後的補充,又是作爲暴力枚舉的操作
        if(i+p[i]-1>R){pos=i;R=i+p[i]-1;}//適時更新pos和R
    }
    int ans=0;
    for(int i=1;i<=len;i++)ans=max(ans,p[i]-1);
	/*
	首先當前的最長迴文子串長度爲2*p[i]-1
	因爲我們得到的p數組是在加了#號後的字符串上操作的,所以我們要對答案進行處理
	因爲#號處於首尾和每個字符之間,所以我們就可以保證所得出的最長迴文子串的首尾都爲#
	這時我們可以得出不帶#號的迴文串的長度爲(2*p[i]-1-1)/2=p[i]-1
	所以真正的最長迴文子串就是p[i]-1
	ans記錄最長的迴文子串長度
	*/
    return ans;
}
int main(){
    while(scanf("%s",s+1)!=EOF){
        printf("%d\n",Manacher());
    }
    return 0;
}
Manacher就是kmp嘛,不就是把原來的那個向右匹配變成向左匹配,程序裏面右註釋,讀註釋去,很好理解的。

查看原文:http://hz2016.tk/blog/?p=23
發佈了127 篇原創文章 · 獲贊 52 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章