[URAL1297 Palindrome]

[关键字]:后缀数组 字符串

[题目大意]:求出给定字符串的最长回文串。

//========================================================================

[分析]:首先把字符串反转(T')接到原串(T)后边中间用‘~’分割(大于所有字符串中元素就行),最后用'$'结束(小于所有字符)。然后枚举T串中的每一个位置i找到T'中对应的位置i'假设以i为中心有一个长度为2r的回文串,那么T[i-r,i-1]=T[i+1,i+r]=T[i'+1,i'+r](画一下就明白了)。所以找以i为中心有一个多长的回文串就可以直接求LCP(i,i'),只要枚举一编T取所有i的最大值就可以了。LCP(i,i')怎么求可以看大牛的论文。

[代码]:

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

const int MAXN=2100;

int len1,len2,n;
int top[MAXN],sa[MAXN],r[MAXN],temp[MAXN],height[MAXN];
int f[MAXN][20];
char s[MAXN],s1[MAXN],s2[MAXN];

void Make()
{
int i,j,len,m;
memset(top,0,sizeof(top));
m=n<256?256:n;
for (i=0;i<n;++i) ++top[r[i]=s[i]&0xff];
for (i=1;i<m;++i) top[i]+=top[i-1];
for (i=0;i<n;++i) sa[--top[r[i]]]=i;
for (len=1;len<n;len<<=1)
{
for (i=0;i<n;++i)
{
j=sa[i]-len;
if (j<0) j+=n;
temp[top[r[j]]++]=j;
}
sa[temp[top[0]=0]]=j=0;
for (i=1;i<n;++i)
{
if (r[temp[i]]!=r[temp[i-1]] ||
r[temp[i]+len]!=r[temp[i-1]+len])
top[++j]=i;
sa[temp[i]]=j;
}
memcpy(r,sa,sizeof(sa));
memcpy(sa,temp,sizeof(sa));
if (j>n-1) break;
}
}

void Lcp()
{
int i,j,k;
for (j=r[height[i=k=0]=0];i<n-1;++i,++k)
while (k>=0 && s[i]!=s[sa[j-1]+k])
height[j]=k--,j=r[sa[j]+1];
}

void RMQ()
{
--n;
for (int i=1;i<=n;++i) f[i][0]=height[i];
int t=(int)floor(log((double)n)/log(2.0));
for (int j=1;j<=t;++j)
for (int i=1;i<=n-(1<<j)+1;++i)
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}

void Solve()
{
int i,x,y,t,temp,ans=0,ansi;
for (int i=0;i<len1;++i)
{
x=r[i],y=r[n-i-1];
if (x>y) swap(x,y);
++x;
t=(int)floor(log((double)y-x+1)/log(2.0));
temp=min(f[x][t],f[y-(1<<t)+1][t]);
if (temp*2-1>ans) ans=temp*2-1,ansi=i-temp+1;
//printf("%d %d %d %d %d %d\n",i,r[i],n-i-1,r[n-i-1],x,y);
x=r[i],y=r[n-i];
if (x>y) swap(x,y);
++x;
t=(int)floor(log((double)y-x+1)/log(2.0));
temp=min(f[x][t],f[y-(1<<t)+1][t]);
if (ans<temp*2) ans=temp*2,ansi=i-temp;
//printf("%d %d %d %d %d %d\n",i,r[i],n-i,r[n-i],x,y);
}
//printf("%d %d\n",ansi,ans);
for (i=ansi;i<=ansi+ans-1;++i) printf("%c",s1[i]);
printf("\n");
}

int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
scanf("%s",s1);
len1=strlen(s1);
for (int i=0;i<len1;++i)
s2[i]=s1[len1-i-1];
len2=strlen(s2);
for (int i=0;i<len1;++i)
s[i]=s1[i];
s[len1]='~';
for (int i=0;i<len2;++i)
s[len1+1+i]=s2[i];
s[len1+len2+1]='$';
n=len1+len2+2;
//printf("%d\n",n);
Make();
Lcp();
RMQ();
//for (int i=0;i<=n;++i) printf("%d ",height[i]);
//printf("\n");
//printf("%d %c\n",n,s[n]);
Solve();
return 0;
}



你可能感兴趣的:(ROM)