1. 程式人生 > >codevs 3160 最長公共子串

codevs 3160 最長公共子串

line name 輸出 () 小寫 long long ems i++ 結果

3160 最長公共子串 時間限制: 2 s 空間限制: 128000 KB 題目等級 : 大師 Master 題目描述 Description

給出兩個由小寫字母組成的字符串,求它們的最長公共子串的長度。

輸入描述 Input Description

讀入兩個字符串

輸出描述 Output Description

輸出最長公共子串的長度

樣例輸入 Sample Input yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother
樣例輸出 Sample Output

27

數據範圍及提示 Data Size & Hint

單個字符串的長度不超過100000
技術分享圖片

最近迷上字符串來hhhhh
這個題的解法比較巧妙,我們把兩個字符串中間隨便加一個不會出現的字符然後連起來做後綴數組,求出height之後,
如果sa[i]和sa[i-1]不在同一字符串中,我們就可以用height[i]更新答案。

這樣得到的答案顯然是最優的,因為求lcp是在height上的rmq,而顯然rank不相鄰的兩個位置答案不會比相鄰的更優。

#include<bits/stdc++.h>
#define ll long long
#define
maxn 200005 using namespace std; char s[maxn]; int sa[maxn],sax[maxn]; int rank[maxn<<1],rankx[maxn]; int cc[maxn],height[maxn]; int n,m,len,ans=0,sec[maxn]; inline int pos(int x){ return x<n; } inline void get_height(){ for(int i=0;i<len;i++) cc[s[i]]++; for(int i=1;i<=500;i++) cc[i]+=cc[i-1
]; for(int i=0;i<len;i++) sa[cc[s[i]]--]=i; for(int i=1;i<=len;i++){ rank[sa[i]]=i; if(i>1&&s[sa[i]]==s[sa[i-1]]) rank[sa[i]]=rank[sa[i-1]]; } int k=1; while(k<len){ memset(cc,0,sizeof(cc)); for(int i=0;i<len;i++) cc[sec[i]=rank[i+k]]++; for(int i=len-1;i>=0;i--) cc[i]+=cc[i+1]; for(int i=0;i<len;i++) sax[cc[sec[i]]--]=i; memset(cc,0,sizeof(cc)); for(int i=0;i<len;i++) cc[rank[i]]++; for(int i=1;i<=len;i++) cc[i]+=cc[i-1]; for(int i=1;i<=len;i++) sa[cc[rank[sax[i]]]--]=sax[i]; for(int i=1;i<=len;i++){ rankx[sa[i]]=i; if(i>1&&rank[sa[i]]==rank[sa[i-1]]&&sec[sa[i]]==sec[sa[i-1]]) rankx[sa[i]]=rankx[sa[i-1]]; } for(int i=0;i<len;i++) rank[i]=rankx[i]; k<<=1; } int now=0,j,mx; for(int i=0;i<len;i++){ if(rank[i]==1){ now=height[rank[i]]=0; continue; } if(now) now--; j=sa[rank[i]-1],mx=max(j,i); while(mx+now<len&&s[i+now]==s[j+now]) now++; height[rank[i]]=now; } } int main(){ scanf("%s",s); n=strlen(s); s[n]=~; scanf("%s",s+n+1); len=strlen(s); get_height(); for(int i=2;i<=len;i++) if(pos(sa[i])^pos(sa[i-1])) ans=max(ans,height[i]); printf("%d\n",ans); return 0; }

codevs 3160 最長公共子串