标签:cal cli dir 计算 cte finish width inpu res
input | output |
---|---|
Kazak |
aza |
给定一个字符串,求最长回文子串。
算法分析:
穷举每一位,然后计算以这个字符为中心的最长回文子串。注意这里要分两种情况,一是回文子串的长度为奇数,二是长度为偶数。两种情况都可以转化为求一个后缀和一个反过来写的后缀的最长公共前缀。具体的做法是:将整个字符串反过来写在原字符串后面,中间用一个特殊的字符隔开。这样就把问题变为了求这个新的字符串的某两个后缀的最长公共前缀。
这个做法的时间复杂度为O(nlogn)。如果RMQ问题用时间为O(n)的方
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<cstdio> 5 #include<algorithm> 6 using namespace std; 7 int const N=2000+3; 8 int wa[N<<1],wb[N<<1],wv[N],rk[N],num[N],sa[N],h[N],L,f[N][12],lg[N<<1]; 9 char s[N<<1]; 10 int cmp(int *r,int x,int y,int z){ 11 return r[x]==r[y] && r[x+z]==r[y+z]; 12 } 13 void build_sa(char *r,int *sa,int n,int m){ 14 int i,j,p,*x=wa,*y=wb; 15 for(i=0;i<m;i++) num[i]=0; 16 for(i=0;i<n;i++) num[x[i]=r[i]]++; 17 for(i=1;i<m;i++) num[i]+=num[i-1]; 18 for(i=n-1;i>=0;i--) sa[--num[x[i]]]=i; 19 for(j=1,p=1;p<n;j<<=1,m=p){ 20 for(p=0,i=n-j;i<n;i++) y[p++]=i; 21 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; 22 for(i=0;i<m;i++) num[i]=0; 23 for(i=0;i<n;i++) num[wv[i]=x[y[i]]]++; 24 for(i=1;i<m;i++) num[i]+=num[i-1]; 25 for(i=n-1;i>=0;i--) sa[--num[wv[i]]]=y[i]; 26 swap(x,y); 27 for(i=1,p=1,x[sa[0]]=0;i<n;i++) 28 x[sa[i]]=cmp(y,sa[i],sa[i-1],j)? p-1:p++; 29 } 30 for(i=0;i<n;i++) rk[i]=x[i]; 31 } 32 void build_h(char *r,int *sa,int n){ 33 int k=0; 34 for(int i=0;i<n;i++){ 35 if(k) k--; 36 int j=sa[rk[i]-1]; 37 while (r[i+k]==r[j+k]) k++; 38 h[rk[i]]=k; 39 } 40 } 41 void build_rmq(int n){ 42 for(int i=0;i<11;i++) 43 for(int j=(1<<i);j<(1<<i+1);j++) 44 lg[j]=i; 45 for(int i=1;i<=n;i++) f[i][0]=h[i]; 46 int k=lg[n]; 47 for(int j=1;j<=k;j++) 48 for(int i=1;i<=n;i++) 49 f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]); // cout<<i<<" "<<j<<" "<<f[i][j]<<endl; 50 } 51 int query(int x,int y){ 52 if(x>y) swap(x,y); 53 x++; 54 int k=lg[y-x+1]; 55 return min(f[x][k],f[y-(1<<k)+1][k]); 56 } 57 58 void solve(int n){ 59 int ans=0,k=n; 60 for(int i=0;i<L-1;i++) { 61 int x=i+1; 62 int y=n-i-1; 63 int z=query(rk[x],rk[y]); 64 if(2*z>ans || 2*z==ans && k>i-z+1){ 65 ans=2*z; 66 k=i-z+1; 67 } 68 } 69 for(int i=0;i<L;i++){ 70 int x=i; 71 int y=n-i-1; 72 int z=query(rk[x],rk[y]); 73 if(2*z-1>ans || 2*z-1==ans && k>i-z+1) { 74 ans=2*z-1; 75 k=i-z+1; 76 } 77 } 78 for(int i=k;i<k+ans;i++) printf("%c",s[i]); 79 printf("\n"); 80 } 81 82 int main(){ 83 scanf("%s",s); 84 int len=strlen(s); 85 L=len; 86 s[len]=123; 87 for(int i=0;i<len;i++) s[len*2-i]=s[i]; 88 len=2*len+1; 89 build_sa(s,sa,len+1,130); 90 build_h(s,sa,len); 91 build_rmq(len); 92 solve(len); 93 return 0; 94 }
标签:cal cli dir 计算 cte finish width inpu res
原文地址:https://www.cnblogs.com/ZJXXCN/p/11001479.html