[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;
}