hihocoder #1032 : 最长回文子串 Manacher算法

题目链接:

https://hihocoder.com/problemset/problem/1032?sid=868170

最长回文子串

时间限制:1000ms
内存限制:64MB
#### 问题描述 > 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。 > > 这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?” > > 小Ho奇怪的问道:“什么叫做最长回文子串呢?” > > 小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串啦~” > > 小Ho道:“原来如此!那么我该怎么得到这些字符串呢?我又应该怎么告诉你我所计算出的最长回文子串呢? > > 小Hi笑着说道:“这个很容易啦,你只需要写一个程序,先从标准输入读取一个整数N(N<=30),代表我给你的字符串的个数,然后接下来的就是我要给你的那N个字符串(字符串长度<=10^6)啦。而你要告诉我你的答案的话,只要将你计算出的最长回文子串的长度按照我给你的顺序依次输出到标准输出就可以了!你看这就是一个例子。”

sample input

3
abababa
aaaabaa
acacdas

sample output

7
5
3

题解

Manacher算法求解最长回文子串
最后答案为max(P[i]-1)

代码

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf

typedef long long  LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;

const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);

//start----------------------------------------------------------------------

const int maxn=2e6+10;

char s[maxn];
//P[i]表示把回文串折叠起来的长度
//mx表示当前计算出来的回文串往右延伸的最远端
//d表示贡献出mx的串的回文中心
int P[maxn],mx,id,n;

int solve(){
    int ret=1;
    int len=strlen(s+1);
    n=len*2+1;
    s[0]='$',s[n]='#',s[n+1]='\0';
    for(int i=len*2;i>=1;i--){
        if(i&1) s[i]='#';
        else s[i]=s[i/2];
    }

    mx=1,id=0;
    for(int i=1;i<=n;i++){
        //优化的核心,画画图比较好理解,j=2*id-i表示i关于id对称的点
        P[i]=mx>i?min(mx-i,P[2*id-i]):1;
        int k=i+P[i];
        while(s[k]==s[2*i-k]) k++,P[i]++;
        if(k>mx){
            mx=k;
            id=i;
        }
        ret=max(ret,P[i]-1);
    }
    return ret;
}

int main() {
    int tc;
    scf("%d",&tc);
    while(tc--){
        scf("%s",s+1);
        int ans=solve();
        prf("%d\n",ans);
    }
    return 0;
}

//end-----------------------------------------------------------------------
posted @ 2016-09-06 00:31  fenicnn  阅读(152)  评论(0编辑  收藏  举报