P1210 回文检测 (manacher算法)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
#define N 20010
char newn[2*N];
char str1[N];
char str2[N];
int pos[N];
int pos2[2*N];
int Len[2*N];
int cnt1,cnt2;
int init(char str[])
{
int i;
newn[0]='$';
newn[1]='#';
int j=2;
for(i=0;i<cnt2;i++)
{
newn[j]=str2[i];
pos2[j]=pos[i]; //因为要用到新的数组了,所以用pos2记录在新数组中ABC在原来数组中的位置
j++;
newn[j++]='#';
}
newn[j]='\0';
return j;
}
int main()
{
int left,right;
int len,i=0,j=0;
int maxn=0,ans=0,po=0,maxlen=-1;
while((str1[i]=getchar())!=EOF)
i++;
cnt1=i;
for(i=0;i<cnt1;i++)
{
if((str1[i]<='z'&&str1[i]>='a')||(str1[i]<='Z'&&str1[i]>='A'))//str2只取ABC字母
{
str2[j]=str1[i];
pos[j]=i; //pos[j]是只记录ABC字母的位置。因为起点与终点一定是ABC字符啊,所以有其他字符在其中间,只要知道开头结尾就行
j++;
}
}
cnt2=j;
for(i=0;i<cnt2;i++)
if(str2[i]<='Z'&&str2[i]>='A')
str2[i]=str2[i]-'A'+'a'; //str2只取小写字母,因为,回文大小写都算,但字符判断确不是这样,所以这样处理
len=init(str2); //init是要返回新数组长度的。
for(i=1;i<len;i++)
{
if(maxn>i)
Len[i]=min(maxn-i,Len[2*po-i]);
else
Len[i]=1;
while(newn[i-Len[i]]==newn[i+Len[i]])//i+-Len[i]
Len[i]++;
if(Len[i]+i>maxn)
{
maxn=Len[i]+i;
po=i;
}
if(maxlen<Len[i]-1)
{
maxlen=Len[i]-1;
left=i-Len[i]+2; //left,刚好是左边界,不算’#‘这个的
right=i+Len[i]-2;//left.right是相对新数组而言的。
}
ans=max(ans,Len[i]);
}
printf("%d\n",ans-1);
for(i=pos2[left];i<=pos2[right];i++)//这里i是取等号。
printf("%c",str1[i]);
printf("\n");
}