Ural 1297 Palindrome(后缀数组+最长回文子串)

https://vjudge.net/problem/URAL-1297

题意:

求最长回文子串。

思路:

先将整个字符串反过来写在原字符串后面,中间需要用特殊字符隔开,那么只需要某两个后缀的最长公共前缀。当然,这两个后缀不是让你随便选的,我们需要先确定回文串的中心(那么这儿就需要注意一下奇偶数的情况了,具体可以看一下代码),确定了中心之后,在后面的逆串中,我们也要找到这个中心点的位置,要求的是这两个后缀的公共前缀。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<stack>
  7 #include<queue>
  8 #include<cmath>
  9 #include<map>
 10 #include<set>
 11 using namespace std;
 12 typedef long long ll;
 13 typedef pair<int,int> pll;
 14 const int INF = 0x3f3f3f3f;
 15 const int maxn=2000+5;
 16 
 17 int n;
 18 char s[maxn];
 19 int sa[maxn],t[maxn],t2[maxn],c[maxn];
 20 int Rank[maxn],height[maxn];
 21 int d[maxn][30];
 22 
 23 void build_sa(int m)
 24 {
 25     int *x=t,*y=t2;
 26     //基数排序
 27     for(int i=0;i<m;i++)    c[i]=0;
 28     for(int i=0;i<n;i++)    c[x[i]=s[i]]++;
 29     for(int i=1;i<m;i++)    c[i]+=c[i-1];
 30     for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
 31     for(int k=1;k<=n;k<<=1)
 32     {
 33         int p=0;
 34         //直接利用sa数组排序第二关键字
 35         for(int i=n-k;i<n;i++)  y[p++]=i;
 36         for(int i=0;i<n;i++)    if(sa[i]>=k)    y[p++]=sa[i]-k;
 37         //基数排序第一关键字
 38         for(int i=0;i<m;i++)    c[i]=0;
 39         for(int i=0;i<n;i++)    c[x[y[i]]]++;
 40         for(int i=1;i<m;i++)    c[i]+=c[i-1];
 41         for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
 42         //根据sa和y计算新的x数组
 43         swap(x,y);
 44         p=1;
 45         x[sa[0]]=0;
 46         for(int i=1;i<n;i++)
 47             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
 48         if(p>=n)
 49             break;
 50         m=p;                //下次基数排序的最大值
 51     }
 52 }
 53 
 54 void getHeight(int n)
 55 {
 56     int i,j,k=0;
 57     for(i=1;i<=n;i++)  Rank[sa[i]]=i;
 58     for(i=0;i<n;i++)
 59     {
 60         if(k)  k--;
 61         int j=sa[Rank[i]-1];
 62         while(s[i+k]==s[j+k])  k++;
 63         height[Rank[i]]=k;
 64     }
 65 }
 66 
 67 void RMQ(int n)
 68 {
 69     for(int i=1;i<=n;i++)  d[i-1][0]=height[i];
 70     for(int j=1;(1<<j)<=n;j++)
 71         for(int i=0;i+(1<<j)-1<n;i++)
 72         d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
 73 }
 74 
 75 int query(int L, int R)
 76 {
 77     int k=0;
 78     while((1<<(k+1))<=R-L+1)  k++;
 79     return min(d[L][k],d[R-(1<<k)+1][k]);
 80 }
 81 
 82 int LCP(int a, int b)
 83 {
 84     int x=Rank[a],y=Rank[b];
 85     if(x>y)  swap(x,y);
 86     x--; y--;
 87     if(y<0)  return 0;
 88     return query(x+1,y);
 89 }
 90 
 91 int main()
 92 {
 93     //freopen("in.txt","r",stdin);
 94     while(~scanf("%s",s))
 95     {
 96         int len = strlen(s);
 97         s[len]='1';
 98         for(int i=0;i<len;i++) s[i+len+1]=s[len-1-i];
 99         s[2*len+1]='0';  //这儿后面的数要加的不一样,一开始两个都加了'0'...
100         n=2*len+2;
101         build_sa(128);
102         getHeight(n-1);
103         RMQ(n-1);
104         int ans=0, tmp, start;
105         for(int i=0;i<len;i++)
106         {
107             tmp=LCP(i,n-i-2);  //长度为奇数的情况
108             if(2*tmp-1>ans)
109             {
110                 ans=2*tmp-1;
111                 start=i-tmp+1;
112             }
113             tmp=LCP(i,n-i-1);  //长度为偶数的情况
114             if(2*tmp>ans)
115             {
116                 ans=2*tmp;
117                 start=i-tmp;
118             }
119         }
120         for(int i=start;i<start+ans;i++)
121             printf("%c",s[i]);
122         printf("
");
123     }
124     return 0;
125 }
原文地址:https://www.cnblogs.com/zyb993963526/p/7580290.html