[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;
}
posted @ 2019-03-31 10:31  Hyscere  阅读(120)  评论(0编辑  收藏  举报