cccc模拟赛有个 求最长回文子串长度的题,一开始看错题了以为是子序列,雪崩。赛后被告知是manacher,然而暴力也能过,我去。
学了一波,找个例题做一下。
题意:求最长回文子串长度
做法:蛮巧妙的,大致是记录一个maxid(之前回文子串的右端点的最大值)和对应的中心坐标id.每次直接扩展半径至p[2*id-i]和maxid-i之间的较小值,再继续扩展,这样就有效避免了重复比对.有效比对次数是maxid从1至n,是o(n)的.稳得不行.
另,做个预处理,每两个之间插个’#’,头尾分别插个奇怪的字符.这样就能不用讨论奇偶,也不会越界.
贴代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char rec[1000500];
char pro[2001000];
int p[2001000];
int main()
{
memset(rec,0,sizeof(rec));
memset(pro,0,sizeof(pro));
char judge[10]="END";
int cnt=0;
while(~scanf("%s",rec))
{
cnt++;
if(!strcmp(judge,rec))break;
int len=strlen(rec);
pro[0]='&';
pro[1]='#';
pro[2*len+2]='$';
for(int i=0;i<len;i++)
{
pro[2*i+2]=rec[i];
pro[2*i+3]='#';
}
int maxid=0,id=0,M=0;
for(int i=1;i<=2*len+1;i++)
{
if(maxid>i)
{
p[i]=min(p[2*id-i],maxid-i+1);
}
else{
p[i]=1;
}
while(pro[i+p[i]]==pro[i-p[i]])
{
p[i]++;
}
if(p[i]+i-1>maxid)
{
maxid=p[i]+i-1;
id=i;
}
if(p[i]>M)M=p[i];
}
printf("Case %d: %d\n",cnt,M-1);
memset(rec,0,sizeof(rec));
memset(pro,0,sizeof(pro));
}
return 0;
}
最近忙于各种考试,智商已欠费,什么第二次期中考试我也是服。刷了一些水(对我这种菜鸡都是水的水),我有罪,检讨。mobius反演的东西也看得头大,先放放吧,过段时间再啃。碎片时间也不好开新专题,随便刷刷吧,就酱。