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

坚强是说给别人听的谎言 提交于 2020-04-05 21:00:22

题目链接:

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

最长回文子串

时间限制:1000ms内存限制:64MB
#### 问题描述 > 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。 > > 这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?” > > 小Ho奇怪的问道:“什么叫做最长回文子串呢?” > > 小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串啦~” > > 小Ho道:“原来如此!那么我该怎么得到这些字符串呢?我又应该怎么告诉你我所计算出的最长回文子串呢? > > 小Hi笑着说道:“这个很容易啦,你只需要写一个程序,先从标准输入读取一个整数N(Nsample 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-----------------------------------------------------------------------
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!