日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

POJ 1743 (后缀数组+不重叠最长重复子串)

發(fā)布時間:2023/12/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 POJ 1743 (后缀数组+不重叠最长重复子串) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題目鏈接:?http://poj.org/problem?id=1743

題目大意:樓教主の男人八題orz。一篇鋼琴譜,每個旋律的值都在1~88以內。琴譜的某段會變調,也就是說某段的數(shù)可以加減一個旋律范圍的值。問這個譜子內最長不重疊的重復部分大小。

解題思路

網(wǎng)上題解已經(jīng)泛濫的題。很多細節(jié)都被先輩大神總結了。

在當年后綴數(shù)組還不是熱門的時候,這題確實是神題。

首先對于旋律變調的處理:

比如123,123,ans=3。

變調之后:456,123,ans=0?不ans=3。

所以不能使用旋律的初始值。應該取每個旋律前后的差值,這樣就能保證某段無論怎么變調,都和原來一樣。

不過這樣就變成n-1個旋律,并且ans會-1,可以拿筆算幾組看看。

?

對于取差值后的n-1個旋律,計算SA和LCP。 ? PS。很多人SA模板都是有問題的,并且推薦自動末尾補0的SA模板,不容易出現(xiàn)問題。

要求不重疊的重復部分大小,這里套用網(wǎng)上被傳承N遍的奇葩結論:

將height數(shù)組分組,每組內的后綴之間的height都要大于len,如果每組內的后綴之間的最長公共前綴有大于len的而且這兩個后綴的SA之差大于len就說明存在長度至少為len的不重復子串。求最長公共前綴就要用到height數(shù)組,因為這組中任意兩個后綴的公共前綴必定是某些height值中的最小值,而這個值如果最大則一定是這組中height中的最大值。

?

由于SA數(shù)組按字典序來的,二分SA數(shù)組長度。如果len符合要求,則先記錄。再向右找更大的,否則向左。注意二分的時候ans初始值為0,不然當n=1的時候,等于沒有二分就return了一個ans。

?

#include "cstring" #include "cstdio" #include "string" #include "iostream" using namespace std; #define maxn 23000 int n,r[maxn],tmp[maxn]; template <class T> inline bool read(T &ret) {char c;int sgn;if(c=getchar(),c==EOF) return 0; //EOFwhile(c!='-'&&(c<'0'||c>'9')) c=getchar();sgn=(c=='-')?-1:1;ret=(c=='-')?0:(c-'0');while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');ret*=sgn;return 1; } struct Suffix {int sa[maxn],rk[maxn],height[maxn];int t[maxn],t2[maxn],c[maxn],m;void init() {m=200;}int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];}void build(){int i,k,p,*x=t,*y=t2;r[n++]=0;for (i=0; i<m; i++) c[i]=0;for (i=0; i<n; i++) c[x[i]=r[i]]++;for (i=1; i<m; i++) c[i]+=c[i-1];for (i=n-1; i>=0; i--) sa[--c[x[i]]]=i;for (k=1,p=1; k<n; k*=2,m=p){for (p=0,i=n-k; i<n; i++) y[p++]=i;for (i=0; i<n; i++) if (sa[i]>=k) y[p++]=sa[i]-k;for (i=0; i<m; i++) c[i]=0;for (i=0; i<n; i++) c[x[y[i]]]++;for (i=1; i<m; i++) c[i]+=c[i-1];for (i=n-1; i>=0; i--) sa[--c[x[y[i]]]]=y[i];swap(x,y);p=1;x[sa[0]]=0;for (i=1; i<n; i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?p-1:p++;}n--;}void LCP(){int i,j,k=0;for (i=1; i<=n; i++) rk[sa[i]]=i;for (i=0; i<n; i++){if (k) k--;j=sa[rk[i]-1];while (r[i+k]==r[j+k]) k++;height[rk[i]]=k;}}bool judge(int len){int l=sa[1],r=sa[1];for(int i=2;i<=n;i++){if(height[i]<len){l=sa[i];r=sa[i];continue;}l=min(l,sa[i]);r=max(r,sa[i]);if(r-l>len) return true;}return false;}int BinarySearch(){int l=0,r=n,mid,ans=0;//注意ans=0,不然當n=1的時候返回的是沒賦值的answhile(l<=r){int mid=l+(r-l)/2;if(judge(mid)) {ans=mid;l=mid+1;}else r=mid-1;}return ans;} }; int main() {//freopen("in.txt","r",stdin);//freopen("out1.txt","w",stdout);while(read(n)&&n){for(int i=0; i<n; i++) read(tmp[i]);for(int i=0; i<n-1; i++) {r[i]=tmp[i+1]-tmp[i]+90;}Suffix a;a.init();a.build();a.LCP();int ans=a.BinarySearch();if(ans<4) printf("0\n");else printf("%d\n",ans+1);} }

?

13560509neopenx1743Accepted840K407MSC++2761B2014-10-24 10:20:38

轉載于:https://www.cnblogs.com/neopenx/p/4047734.html

總結

以上是生活随笔為你收集整理的POJ 1743 (后缀数组+不重叠最长重复子串)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。