其他分享
首页 > 其他分享> > [BZOJ2565] 最长双回文串

[BZOJ2565] 最长双回文串

作者:互联网

题目链接

BZOJ.

洛谷.

Solution

随便跳的题...

先跑一边\(manacher\)。

很容易想到一个做法,处理出\(l[i]\)表示以\(i\)结尾的回文串最大长度,\(r[i]\)表示以\(i\)开头。

那么如何处理出这个呢,可以发现,\(l[i]\)其实就是回文中心离\(i\)最远的,且回文可以波及到\(i\)。

那么直接拿个指针指一下扫过去就好了。

最后处理答案就是枚举断点,前面是\(l[i]\)后面是\(r[i]\)。

细节还是有一点的。

#include<bits/stdc++.h>
using namespace std;

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

#define lf double
#define ll long long 

const int maxn = 2e5+10;
const int inf = 1e9;
const lf eps = 1e-8;

char c[maxn],s[maxn];
int n,mid,mr,m,p[maxn],l[maxn],r[maxn];

void solve(int *res) {
    memset(p,0,sizeof p);n=0;
    m=strlen(c+1);s[0]='$',s[++n]='#';
    for(int i=1;i<=m;i++) s[++n]=c[i],s[++n]='#';mid=mr=1;
    for(int i=1;i<=n;i++) {
        p[i]=min(p[mid*2-i],mr-i);
        while(s[i+p[i]]==s[i-p[i]]) p[i]++;
        if(i+p[i]>mr) mr=i+p[i],mid=i;
    }
    
    int t=1;
    for(int i=1;i<=n;i++) {
        while(t+p[t]-1<i) t++;
        res[i]=(i-t)*2+1;
    }
}

int main() {
    scanf("%s",c+1);solve(l);
    reverse(c+1,c+strlen(c+1)+1);
    solve(r);int ans=0;reverse(r+1,r+n+1);
    for(int i=2;i<n-1;i+=2) ans=max(ans,l[i]/2+1+r[i+2]/2+1);
    for(int i=3;i<n;i+=2) ans=max(ans,max(l[i]/2+r[i+1]/2+1,l[i-1]/2+1+r[i]/2));
    write(ans);
    return 0;
}

标签:ch,int,void,isdigit,BZOJ2565,回文,最长,getchar
来源: https://www.cnblogs.com/hbyer/p/10630421.html