題目名稱:最長迴文子串
題目鏈接:http://hihocoder.com/problemset/problem/1032
描述
小Hi和小Ho是一對好朋友,出生在信息化社會的他們對編程產生了莫大的興趣,他們約定好互相幫助,在編程的學習道路上一同前進。
這一天,他們遇到了一連串的字符串,於是小Hi就向小Ho提出了那個經典的問題:“小Ho,你能不能分別在這些字符串中找到它們每一個的最長迴文子串呢?”
小Ho奇怪的問道:“什麼叫做最長迴文子串呢?”
小Hi回答道:“一個字符串中連續的一段就是這個字符串的子串,而回文串指的是12421這種從前往後讀和從後往前讀一模一樣的字符串,所以最長迴文子串的意思就是這個字符串中最長的身爲迴文串的子串啦~”
小Ho道:“原來如此!那麼我該怎麼得到這些字符串呢?我又應該怎麼告訴你我所計算出的最長迴文子串呢?
小Hi笑着說道:“這個很容易啦,你只需要寫一個程序,先從標準輸入讀取一個整數N(N<=30),代表我給你的字符串的個數,然後接下來的就是我要給你的那N個字符串(字符串長度<=10^6)啦。而你要告訴我你的答案的話,只要將你計算出的最長迴文子串的長度按照我給你的順序依次輸出到標準輸出就可以了!你看這就是一個例子。”
提示一 提示二 提示三 提示四3 abababa aaaabaa acacdas樣例輸出
7 5 3
思路;看原題提示,用manacher算法,可以直接模板,不過建議理解,其實挺好玩的
代碼如下:
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1000005;
char str[maxn]; //原字符串
char tmp[maxn<<1]; //轉換後的字符串
int Len[maxn<<1];
int INIT(char* st)
{
int len=strlen(st);
tmp[0]='@'; //字符串開頭增加一個特殊字符,防止越界
for(int i=1;i<=len*2;i+=2)
{
tmp[i]='#';
tmp[i+1]=st[i/2];
}
tmp[2*len+1]='#';
tmp[2*len+2]='$'; //字符串結尾加一個字符,防止越界,注意不要再次用'@'
return 2*len+1; //返回轉換字符串的長度
}
int Manacher(char* st,int len)
{
int mx=0,po=0,ans=0; //mx即爲當前計算迴文串最右邊字符的最大值,po爲取得最右邊時的中間值
for(int i=1;i<=len;i++)
{
if(mx>i)
Len[i]=min(mx-i,Len[2*po-i]);//在Len[j]和mx-i中取個小
else
Len[i]=1;//如果i>=mx,要從頭開始匹配
while(st[i-Len[i]]==st[i+Len[i]])
Len[i]++;
if(Len[i]+i>mx)//若新計算的迴文串右端點位置大於mx,要更新po和mx的值
{
mx=Len[i]+i;
po=i;
}
ans=max(ans,Len[i]);
}
return ans-1;//返回Len[i]中的最大值-1即爲原串的最長迴文子串額長度
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%s",str);
printf("%d\n",Manacher(tmp,INIT(str)));
}
}
return 0;
}