https://vjudge.net/problem/URAL-1297
题意:
给出一个字符串求最长回文子串
代码:
//论文题,把字符串反过来复制一遍到后边,中间用一个没出现的字符隔开,然后就是枚举当以i位置为中间位时的最长回文串 //是多大,就是求这中间的heigh数组的最小值。用rmq预处理。枚举位置时分回文串长度是奇数还是偶数。 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXN=3000; int sa[MAXN+9],ra[MAXN+9],he[MAXN+9],buc[MAXN+9],xx[MAXN+9],yy[MAXN+9],f[MAXN+9][30]; int len,m; char s[MAXN+9]; void get_suf() { int *x=xx,*y=yy; for(int i=0;i<m;i++) buc[i]=0; for(int i=0;i<len;i++) buc[x[i]=s[i]]++; for(int i=1;i<m;i++) buc[i]+=buc[i-1]; for(int i=len-1;i>=0;i--) sa[--buc[x[i]]]=i; for(int k=1;k<=len;k<<=1){ int p=0; for(int i=len-1;i>=len-k;i--) y[p++]=i; for(int i=0;i<len;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0;i<m;i++) buc[i]=0; for(int i=0;i<len;i++) buc[x[y[i]]]++; for(int i=1;i<m;i++) buc[i]+=buc[i-1]; for(int i=len-1;i>=0;i--) sa[--buc[x[y[i]]]]=y[i]; swap(x,y); p=1;x[sa[0]]=0; for(int i=1;i<len;i++){ if(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]) x[sa[i]]=p-1; else x[sa[i]]=p++; } if(p>=len) break; m=p; } for(int i=0;i<len;i++) ra[sa[i]]=i; int k=0; for(int i=0;i<len;i++){ if(ra[i]==0) { he[0]=0; continue; } if(k) k--; int j=sa[ra[i]-1]; while(s[i+k]==s[j+k]&&i+k<len&&j+k<len) k++; he[ra[i]]=k; } } void rmq1(int n) { for(int i=0;i<n;i++) f[i][0]=he[i]; for(int j=1;(1<<j)<n;j++){ for(int i=0;i+(1<<j)-1<n;i++) f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]); } } int rmq2(int l,int r) { if(r<l) swap(r,l); l++; int k=0; while(1<<(k+1)<=r-l+1) k++; return min(f[l][k],f[r-(1<<k)+1][k]); } int main() { while(scanf("%s",s)==1){ int x=strlen(s); s[x]='0'; len=x+1; for(int i=x-1;i>=0;i--) s[len++]=s[i]; m=200; get_suf(); rmq1(len); int id=0,max_len=1; for(int i=0;i<x;i++){ int tmp; if(i!=0){ tmp=rmq2(ra[i],ra[2*x-i+1]); if(tmp*2>max_len){ max_len=tmp*2; id=i-tmp; } } if(i!=x&&i!=0){ tmp=rmq2(ra[i],ra[2*x-i]); if(tmp*2-1>max_len){ max_len=tmp*2-1; id=i-tmp+1; } } } for(int i=id;i<id+max_len;i++) printf("%c",s[i]); printf(" "); } return 0; }