hdu 5371 Hotaru's problem (Manacher算法)

给n个数,求满足条件的子串的最长长度。

条件:整个数字串可分为三段,前两段和后两段均为回文串。


解法:先用manacher算法求出各个位置为中心的回文长度,然后分别枚举前两段和后两段的对称中心,即枚举中间那段的长度。由于manacher算法求出来的每个中心的回文长度是最长的,因此只要有后两段的回文串的最长回文半径大于等于所枚举的长度,就可以更新答案。

时间复杂度为O(n)


关于manacher算



#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cstring>
#include<vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef __int64 LI;
typedef unsigned __int64 uLI;
typedef unsigned int uI;
typedef double db;
#define maxn 100005
#define inf 0x3f3f3f3f
int n,p[maxn<<1];
int a[maxn<<1],b[maxn];
void Manacher(){
    int i,mx=0,id;
    for(i=1;i<=n;++i)
    {
        if(mx>i) p[i]=min(mx-i,p[2*id-i]);
        else p[i]=1;
        for(;a[i+p[i]]==a[i-p[i]];p[i]++);
        if(p[i]+i>mx){
            mx=p[i]+i;
            id=i;
        }
    }
}

int main()
{
    int i,j,ca=1,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;++i) scanf("%d",&b[i]);
        a[0]=-2,a[1]=-1;
        for(i=1;i<=n;++i){
            a[i*2]=b[i];
            a[i*2+1]=-1;
        }
        n=2*n+1;
        Manacher();
        int ans=-1;
        for(i=1;i<=n;i+=2)
            for(j=i+p[i]-1;j-i+1>ans;j-=2)
                if(p[j]>=j-i+1) ans=j-i+1;
        printf("Case #%d: %d\n",ca++,(ans-1)/2*3);
    }
    return 0;
}


你可能感兴趣的:(hdu 5371 Hotaru's problem (Manacher算法))