Description
Input
Output
Sample Input
input | output |
---|---|
ThesampletextthatcouldbereadedthesameinbothordersArozaupalanalapuazorA |
ArozaupalanalapuazorA |
和我做的第一题
真是蛮像的,求一个字符串的最长回文串,但是后缀数组求得是从前往后方向的,那怎么办,把这个字符串掉个个接到后面,逐位匹配,分奇偶的讨论一下,还有,通过位置找区间最小值的时候调用的是lcp函数啊啊啊,不是ansRMQ,这个错误太弱智了==
/********** ural1297 2016.2.22 540 15 G++ 4.9 **********/ #include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> using namespace std; const int MAXN=2010; int sa[MAXN];//SA数组,表示将S的n个后缀从小到大排序后把排好序的 //的后缀的开头位置顺次放入SA中 int t1[MAXN],t2[MAXN],c[MAXN];//求SA数组需要的中间变量,不需要赋值 int rank[MAXN],height[MAXN]; void build_sa(int s[],int n,int m) { int i,j,p,*x=t1,*y=t2; //第一轮基数排序,如果s的最大值很大,可改为快速排序 for(i=0;i<m;i++)c[i]=0; for(i=0;i<n;i++)c[x[i]=s[i]]++; for(i=1;i<m;i++)c[i]+=c[i-1]; for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i; for(j=1;j<=n;j<<=1) { p=0; //直接利用sa数组排序第二关键字 for(i=n-j;i<n;i++)y[p++]=i;//后面的j个数第二关键字为空的最小 for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; //这样数组y保存的就是按照第二关键字排序的结果 //基数排序第一关键字 for(i=0;i<m;i++)c[i]=0; for(i=0;i<n;i++)c[x[y[i]]]++; for(i=1;i<m;i++)c[i]+=c[i-1]; for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; //根据sa和x数组计算新的x数组 swap(x,y); p=1;x[sa[0]]=0; for(i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++; if(p>=n)break; m=p;//下次基数排序的最大值 } } void getHeight(int s[],int n) { int i,j,k=0; for(i=0;i<=n;i++)rank[sa[i]]=i; for(i=0;i<n;i++) { if(k)k--; j=sa[rank[i]-1]; while(s[i+k]==s[j+k])k++; height[rank[i]]=k; } } int RMQ[MAXN]; int mm[MAXN]; int best[20][MAXN]; void initRMQ(int n) { mm[0]=-1; for(int i=1;i<=n;i++) mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; for(int i=1;i<=n;i++)best[0][i]=i; for(int i=1;i<=mm[n];i++) for(int j=1;j+(1<<i)-1<=n;j++) { int a=best[i-1][j]; int b=best[i-1][j+(1<<(i-1))]; if(RMQ[a]<RMQ[b])best[i][j]=a; else best[i][j]=b; } } int askRMQ(int a,int b) { int t; t=mm[b-a+1]; b-=(1<<t)-1; a=best[t][a];b=best[t][b]; return RMQ[a]<RMQ[b]?a:b; } int lcp(int a,int b) { a=rank[a];b=rank[b]; if(a>b)swap(a,b); return height[askRMQ(a+1,b)]; } int r[MAXN]; char str[MAXN]; int main() { // freopen("cin.txt","r",stdin); while(~scanf("%s",str)) { int len=strlen(str); for(int i=0;i<len;i++) r[i]=str[i]; r[len]=1; for(int i=0;i<len;i++) r[len+1+i]=str[len-1-i]; r[len*2+1]=0; int n=len*2+1; build_sa(r,n+1,128); getHeight(r,n); for(int i=1;i<=n;i++)RMQ[i]=height[i]; //for(int i=1;i<=n;i++) printf("i=%d,rmq=%d\n",i,RMQ[i]); initRMQ(n); int ans=0,st=0; for(int i=0;i<len;i++) { //偶对称 int tmp=lcp(i,n-i); if(tmp*2>ans) { ans=tmp*2; st=i-tmp; // printf("even ans=%d i=%d st=%d\n",ans,i,st); } //奇对称 tmp=lcp(i,n-i-1); if(tmp*2-1>ans) { ans=tmp*2-1; st=i-tmp+1; // printf("odd ans=%d i=%d st=%d\n",ans,i,st); } } //printf("st=%d ans=%d ",st,ans); str[st+ans]=0; printf("%s\n",str+st); } return 0; }