ural 1297. Palindrome

时间:2024-03-22 09:06:50

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1297

求最长回文子串

典型的后缀数组的入门题目,但是可以用更简单的方法解决,毕竟数据量比较小啊

转载:

题目大意:给出一个字符串,求它的连续最长回文子串。

分析:这题数据规模不大(n<=1000),所以直接暴力可以解决。不过如果数据规模大了,暴力就不行了。这里介绍后缀数组的做法。

首先,枚举回文子串的中心所在位置。这里要分回文串长度为奇数和偶数两种情况考虑。这两个问题均可以转化为求一个后缀和一个倒着写的后缀的最长公共前缀。

具体地,将原串与反着写之后的原串相连,中间以一个特殊字符隔开。这个特殊字符只要不是0号,不影响后缀的排序,就没有问题。(不能是0是因为我的倍增算法要求除了字符串的最后一位以外,其它位不能为0,否则会出错)然后算出height数组。两个后缀的最长公共前缀为两个后缀排序之后,它们之间的串的height值的最小值。这个可以自己举个具体例子好好体会。用st算法求解rmq问题即可。

********************************************************************************************************************************************************************************************************************

代码如下:

 #include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=;
int n,w[maxn],wa[maxn],wb[maxn],wv[maxn];
int a[maxn],sa[maxn],rank[maxn],height[maxn],f[maxn][];
int cmp(int *r,int a,int b,int l){
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int *r,int *sa,int n,int m){
int i,j,p,*x=wa,*y=wb,*t;
for (i=;i<m;i++) w[i]=;
for (i=;i<n;i++) w[x[i]=r[i]]++;
for (i=;i<m;i++) w[i]+=w[i-];
for (i=n-;i>=;i--) sa[--w[x[i]]]=i;
for (p=,j=;p<n;m=p){
for (p=,i=n-j;i<n;i++) y[p++]=i;
for (i=;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j;
for (i=;i<m;i++) w[i]=;
for (i=;i<n;i++) w[wv[i]=x[y[i]]]++;
for (i=;i<m;i++) w[i]+=w[i-];
for (i=n-;i>=;i--) sa[--w[wv[i]]]=y[i];
for (t=x,x=y,y=t,p=,x[sa[]]=,i=;i<n;i++)
x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
}
return;
}
void calheight(int *r,int *sa,int n){
int i,j,k=;
for (i=;i<=n;i++) rank[sa[i]]=i;
for (i=;i<n;height[rank[i++]]=k)
for (k?k--:,j=sa[rank[i]-];r[i+k]==r[j+k];k++);
return;
}
void rmq(int *rank,int n){
int i,j;
memset(f,,sizeof(f));
for (i=;i<=n;i++) f[i][]=height[i];
for (j=;j<;j++)
for (i=;i+(<<j)-<=n;i++)
f[i][j]=min(f[i][j-],f[(<<(j-))+i][j-]);
return;
}
int get_rmq(int x,int y){
int a=rank[x],b=rank[y];
if (a>b) {int t=a; a=b; b=t;}
a++;
int t=int(log(double(b-a+))/log(2.00));
return min(f[a][t],f[b-(<<t)+][t]);
}
int main(){
char s[maxn];
cin >> s;
n=strlen(s);
int i,ans=,k=;
for (i=;i<n;i++) a[i]=s[i];
a[n]=;
for (i=;i<n;i++) a[i+n+]=s[n--i];
a[*n+]=;
da(a,sa,*n+,);
calheight(a,sa,*n+);
rmq(rank,*n+);
for (i=;i<n;i++){
int t=get_rmq(i,*n-i)*-;
if (t>ans)
{
ans=t;
k=i;
}
if (i>)
{
t=get_rmq(i,*n-i+)*;
if (t>ans)
{
ans=t;
k=i;
}
}
}
if (ans%!=) for (i=k-ans/;i<=k+ans/;i++) cout<<s[i];
else for (i=k-ans/;i<k+ans/;i++) cout<<s[i];
cout<<endl;
return ;
}