馬拉車manacher板子

wxz0v0發表於2020-10-23

馬拉車就是在字串中間加上’#'使得無論字串長度為奇或偶都為偶,而且如果mx<i,則為第一種情況,
先確定mx以內的迴文串,馬拉車就快在這(不用從頭向兩邊尋找),再向兩邊延伸,注意的是len[i]=min(mx-i,len[2*po-i]);這個2po-i是如何得來的,設i關於po的對稱點為j那麼len[j]=len[i]可以肯定,(i+j)/2=po可以推出j=2po-i.
另一種情況是i>mx就需要直接從i向兩邊暴力求了
洛谷P3805

#include<bits/stdc++.h>
#include<ext/rope>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a));
#define ll long long int
const int INF = 0x3f3f3f3f;
const int maxn = 11000000;
char str[maxn+10];
char temp[maxn*2+10];
int len[maxn*2+10];
int max1=0;
void init(int len1)
{
    temp[0]='@';
    for(int i=1;i<=2*len1;i+=2)
    {
        temp[i]='#';
        temp[i+1]=str[i/2];
    }
    temp[2*len1+1]='#';
    temp[2*len1+2]='$';
    temp[2*len1+3]=0;
}
void manacher(int nlen)
{
    int mx=0,ans=0,po=0;
    for(int i=1;i<=nlen;++i)
    {
        if(mx>i)
            len[i]=min(mx-i,len[2*po-i]);//(i+j)/2==po推出j=2*po-i,且右側不得大於mx
        else
            len[i]=1;
        while(temp[i-len[i]]==temp[i+len[i]])
            len[i]++;
        if(i+len[i]>mx)
        {
            po=i;
            mx=i+len[i];
        }
        len[i]--;
        if(len[i]>max1)
            max1=len[i];
    }
}
int main()
{
    int len1,nlen;
    scanf("%s",str);
    len1=strlen(str);
    init(len1);
    nlen=strlen(temp);
    manacher(nlen);
    printf("%d\n",max1);
    return 0;
}