URAL 1297. Palindrome(后缀数组 求最长回文子串)
题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1297
1297. Palindrome
Memory limit: 64 MB
In addition, it is reasonable to assume that the agent will be sending a very long message, so John has simply to find the longest message satisfying the mentioned property.
Input
Output
Sample
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; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。