容斥刷不动啊!!今天十分的邪恶加猥琐的注册了一个小号和大一的孩子们一起做题;
也没有要和他们比赛的意思,只是我对算法有很多不熟悉的,所以呢....哎 我的号交几个题,小号交几个题。
做都做了,不管了。
晚上花了一个半小时才看懂的一个算法Manacher,专门用来做回文的....
网上其他的人写得佷详细了,我还是说说自己的吧。
Manacher利用了回文的性质。
假设有一个回文以id为中点,p[id]是这个回文的半径。
那么id右边的点i,若点i在id控制的回文串的范围内。
则i关于id对称的点j,通过几何性质可得出j=id*2-i;
则以j为中点的回文串的左边界若处于id回文串的左边界以内。
则由回文的性质可得知p[i]与p[j]是等价的。
因为以j为中心的字符串完全在id的回文串内,若j所决定的回文串超出了id的左边界.
那么以i为中心的字符串最长为mx-i,也就是i离mx的距离为p[i],i的回文长度。
做完这一步再由i向左右拓展,使得回文串增长。
这样达到的最右边mx进行更新。
大体的算法就是这样了:
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
int p[2222222];
char str[1111111],str1[2222222];
int len;
void Init()
{
str1[0]='$';
str1[1]='#';
len=2;
for( int i=0;str[i]!=0;i++ )
{
str1[len++]=str[i];
str1[len++]='#';
}
str1[len]=0;
}
int main()
{
int T=0;
while( scanf("%s",&str)!=EOF )
{
if( strlen(str)==3 && str[0]=='E' && str[1]=='N' && str[2]=='D' )
break;
//memset( str1,0,sizeof(str1) );
memset( p,0,sizeof(p) );
Init();
int id,mx=0;
for( int i=1;i<len;i++ )
{
if( mx>i )
p[i]=min(p[(id<<1)-i],mx-i);
else
p[i]=1;
while( str1[i-p[i]]==str1[i+p[i]] )
p[i]++;
if( mx<i+p[i] );
{
mx=i+p[i];
id=i;
}
}
printf( "Case %d: ",++T );
int ans=0;
for( int i=1;i<len;i++ )
ans=max(p[i],ans);
printf( "%d\n",ans-1 );
}
return 0;
}