【题目链接】
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12406
【题意】
求最长回文子串。
【思路】
将字符串反向拼接在后,中间用一个没有出现的字符隔开,则问题转化为求新字符串两个特定后缀的lcp,枚举对称点i,对称数为奇的情况对应求lcp(i,n-i),对称数为偶的情况对应求lcp(i,n-i-1)。
如图所示:
两个后缀的lcp可以用Sparse Table算法(倍增)在O(nlogn)时间内求解。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 5 using namespace std; 6 7 const int maxn = 3000+10; 8 const int maxd = 22; 9 10 int s[maxn]; 11 int sa[maxn],c[maxn],t[maxn],t2[maxn]; 12 13 void build_sa(int m,int n) { 14 int i,*x=t,*y=t2; 15 for(i=0;i<m;i++) c[i]=0; 16 for(i=0;i<n;i++) c[x[i]=s[i]]++; 17 for(i=1;i<m;i++) c[i]+=c[i-1]; 18 for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i; 19 20 for(int k=1;k<=n;k<<=1) { 21 int p=0; 22 for(i=n-k;i<n;i++) y[p++]=i; 23 for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; 24 25 for(i=0;i<m;i++) c[i]=0; 26 for(i=0;i<n;i++) c[x[y[i]]]++; 27 for(i=0;i<m;i++) c[i]+=c[i-1]; 28 for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; 29 30 swap(x,y); 31 p=1; x[sa[0]]=0; 32 for(i=1;i<n;i++) 33 x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++; 34 if(p>=n) break; 35 m=p; 36 } 37 } 38 int rank[maxn],height[maxn]; 39 void getHeight(int n) { 40 int i,j,k=0; 41 for(i=0;i<=n;i++) rank[sa[i]]=i; 42 for(i=0;i<n;i++) { 43 if(k) k--; 44 j=sa[rank[i]-1]; 45 while(s[j+k]==s[i+k]) k++; 46 height[rank[i]]=k; 47 } 48 } 49 int A[maxn][maxd]; 50 void RMQ_init(int n) { 51 for(int i=1;i<=n;i++) A[i-1][0]=height[i]; 52 for(int k=1;(1<<k)<=n;k++) 53 for(int i=0;(i+(1<<k))<=n;i++) 54 A[i][k]=min(A[i][k-1],A[i+(1<<(k-1))][k-1]); 55 } 56 int query(int l,int r) { 57 int k=0; 58 while(1<<(k+1)<=(r-l+1)) k++; 59 return min(A[l][k],A[r-(1<<k)+1][k]); 60 } 61 int lcp(int a,int b) { 62 int l=rank[a],r=rank[b]; 63 if(r<l) swap(l,r); l--,r--; 64 if(r<0) return 0; 65 return query(l+1,r); //l+1 66 } 67 68 int n; 69 char expr[maxn]; 70 71 int main() { 72 while(scanf("%s",expr)==1) { 73 int len=strlen(expr),n=2*len+1; 74 for(int i=0;i<len;i++)s[i]=expr[i]; 75 s[len]=1; 76 for(int i=0;i<len;i++)s[i+len+1]=expr[len-1-i]; 77 s[n]=0; 78 79 build_sa('z'+1,n+1); 80 getHeight(n); 81 RMQ_init(n); 82 int ans=0,front,tmp; 83 for(int i=0;i<n;i++) { 84 tmp=lcp(i,n-i-1); 85 if(2*tmp-1>ans) { //对称个数为奇数 86 ans=2*tmp-1; 87 front=i-tmp+1; 88 } 89 tmp=lcp(i,n-i); 90 if(2*tmp>ans) { //对称个数为偶数 91 ans=2*tmp; 92 front=i-tmp; 93 } 94 } 95 expr[front+ans]='