题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1297
| input | output |
|---|---|
ThesampletextthatcouldbereadedthesameinbothordersArozaupalanalapuazorA |
ArozaupalanalapuazorA |
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 2047
int wa[N], wb[N], wv[N], ws1[N];
int rank1[N]; //名次数组
int height[N]; //排名相邻的两个后缀的最长公共前缀
int sa[N]; //sa为后缀数组,n个后缀从小到大进行排序之后把排好序的后缀的开头位置
char s[N];
int a[N], n;
int dp[N][47];
int minn(int a,int b)
{
return a>b?b:a;
}
int cmp(int *r,int a,int b,int l)
{
return r[a]==r[b] && r[a+l]==r[b+l];
}
void get_sa(int *r, int *sa, int n, int m) //倍增算法
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0; i<m; i++) ws1[i]=0;
for(i=0; i<n; i++) ws1[x[i]=r[i]]++;
for(i=1; i<m; i++) ws1[i]+=ws1[i-1];
for(i=n-1; i>=0; i--) sa[--ws1[x[i]]]=i; //对长度为1的字符串排序
for(p=1,j=1; p<n; j*=2,m=p)
{
for(p=0,i=n-j; i<n; i++) y[p++]=i;
for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j; //第二关键字排序结果
for(i=0; i<n; i++) wv[i]=x[y[i]];
for(i=0; i<m; i++) ws1[i]=0;
for(i=0; i<n; i++) ws1[wv[i]]++;
for(i=1; i<m; i++) ws1[i]+=ws1[i-1];
for(i=n-1; i>=0; i--) sa[--ws1[wv[i]]]=y[i]; //第一关键字排序
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; //更新rank数组
}
return;
}
void get_height(int *r, int *sa, int n) //求height数组
{
int i, j, k=0;
for(i=1; i<=n; i++) rank1[sa[i]]=i;
for(i=0; i<n; height[rank1[i++]]=k)
for(k?k--:0,j=sa[rank1[i]-1]; r[i+k]==r[j+k]; k++);
return;
}
void RMQ()
{
memset(dp,127,sizeof(dp));
for(int i = 1; i <= n*2+1; i++)
dp[i][0] = height[i];
for(int j = 1; (1<<j) <= 2*n+1; j++)
for(int i = 1; i+(1<<j)-1 <= 2*n+1; i++)
dp[i][j] = minn(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int lcp(int l,int r)//求最长公共前缀
{
int a = rank1[l], b = rank1[r];
if(a > b)
swap(a,b);
a++;
int t=(int)(log(double(b-a+1))/log(2.00));
return minn(dp[a][t],dp[b-(1<<t)+1][t]);
}
int main()
{
int res;
while(~scanf("%s",s))
{
int maxx = 0;
n = strlen(s);
for(int i = 0; i < n; i++)
a[i] = (int)s[i];
a[n] = 1;
for(int i = 0; i < n; i++)
a[i+n+1] = (int)s[n-i-1];
int LEN = 2*n+1;
a[LEN] = 0;
get_sa(a,sa,LEN+1,320);
get_height(a,sa,LEN);
RMQ();
int anslen = 0, idx = 0;
for(int i = 0; i < n; i++)
{
int t = lcp(i,LEN-i-1);
if(2*t-1 > anslen)//多算了一次中心字母
{
anslen = 2*t-1;
idx = i;
}
if(s[i] == s[i+1])
{
t = lcp(i+1,LEN-i-1);
if(2*t > anslen)
{
anslen = 2*t;
idx = i;
}
}
}
idx = idx-(anslen-1)/2;
for(int i = 0; i < anslen; i++)
printf("%c",s[idx+i]);
printf("\n");
}
return 0;
}
URAL 1297. Palindrome(后缀数组 求最长回文子串)
原文地址:http://blog.csdn.net/u012860063/article/details/44118887