【bzoj2342】 SHOI2011 双倍回文 manacher+set

学习了一下manacher,这个算法是用来求字符串中以每一项为对称轴的最长回文子串长度的。

放一下链接:http://blog.csdn.net/ggggiqnypgjg/article/details/6645824/

大概用的一个思想就是利用对称,考虑当前覆盖到的最右端(假设为id+p[id]),那么我们可以利用对称性,前面的子串是已经求过的,i的回文子串长度就至少为i关于id对称点的最长回文字串长度,还有一种情况是mx后面的并没有匹配到,所以要这两项取一个最小值。然后为了处理起来方便,就在每两个字符间加一个#号,这样就可以把奇回文子串与偶回文子串一并讨论,最后原串中回文子串长就是p[id]-1。


这道题想了一下,去膜拜一下黄学长的题解。

http://hzwer.com/5375.html

枚举对称轴x,考虑用len(x+1,y)*4更新答案,则必须满足y-p[y]<=x,y<=x+p[x]/2。

那么我们按照y-p[y]排序后,依次插入set,每次询问比x+p[x]/2小的最大值就可以了。

注意:本题只讨论长度为偶数的回文子串,所以不需要加上#号。


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#define maxn 500010

using namespace std;

struct yts
{
	int x,y;
}a[maxn];

int n;
int p[maxn];
set<int> s;
char ch[2*maxn];

void manacher()
{
	int mx=0,id=0;
	for (int i=1;i<=n;i++)
	{
		if (mx>i) p[i]=min(p[id*2-i],mx-i);
		else p[i]=0;
		while (ch[i+p[i]+1]==ch[i-p[i]]) p[i]++;
		if (i+p[i]>mx)
		{
			mx=i+p[i];
			id=i;
		}
	}
}

bool cmp(yts x,yts y)
{
	return x.x<y.x;
}

int main()
{
	scanf("%d",&n);
	scanf("%s",ch+1);ch[0]='#';
	manacher();
	//for (int i=1;i<=n;i++) printf("%d ",p[i]);printf("\n");
	for (int i=1;i<=n;i++) a[i].x=i-p[i],a[i].y=i;
	sort(a+1,a+n+1,cmp);
	int ans=0,top=0;
	for (int i=1;i<=n;i++)
	{
		while (top<n && a[top+1].x<=i) top++,s.insert(a[top].y);
		ans=max(ans,(*--s.lower_bound(i+p[i]/2+1)-i)*4);
	}
	printf("%d\n",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值