POJ 1743 后缀数组
题意:一道论文题,给定一串数组,求最长的重复子串长度,其中这两个子串不重叠,这两个子串可以相差同一个数字。
分析:后一个减前一个数字,那么对于上面说的,可以相差同一个数字就变成了相同数字。问题就变成了,求一个串里面的最长不可重复的子串长度。
但是不再是height数组里面的最大值了,二分答案,将height分成若干组(height数组是已经根据sa数组排好了的),记录每组里面的sa[] 最小值,sa[] 最大值,L + mid + 1<=R 即不重叠。
最后大佬模板就是硬!
#include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1000000+5; int wa[maxn],wb[maxn],wv[maxn],ws[maxn]; int sa[maxn]; int r[maxn]; int cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0; i<m; i++) ws[i]=0; for(i=0; i<n; i++) ws[x[i]=r[i]]++; for(i=1; i<m; i++) ws[i]+=ws[i-1]; for(i=n-1; i>=0; i--) sa[--ws[x[i]]]=i; for(j=1,p=1; p<n; j*=2,m=p) { for(p=0,i=n-j; i<n; i++) y[p++]=i; for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0; i<n; i++) wv[i]=x[y[i]]; for(i=0; i<m; i++) ws[i]=0; for(i=0; i<n; i++) ws[wv[i]]++; for(i=1; i<m; i++) ws[i]+=ws[i-1]; for(i=n-1; i>=0; i--) sa[--ws[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } return; } int rank[maxn],height[maxn]; void calheight(int *r,int *sa,int n) { int i,j,k=0; for(i=1; i<=n; i++) rank[sa[i]]=i; for(i=0; i<n; height[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++); return; } int a[maxn]; int n; const int INF = 0x3f3f3f3f; int main() { //freopen("in.txt","r",stdin); while(scanf("%d",&n),n) { for(int i=0; i<n; i++) scanf("%d",&a[i]); for(int i=0; i<n-1; i++) { r[i] = a[i+1] - a[i]+100; } n--; da(r,sa,n+1,300); calheight(r,sa,n); int l = 1,r=n+1,mid; int L,R; while(l<=r) { mid = (l+r)/2; L = INF,R = -INF; bool flag = false; for(int i=1; i<=n; i++) { if(height[i]>=mid) { L = min(L,sa[i]); L = min(L,sa[i-1]); R = max(R,sa[i]); R = max(R,sa[i-1]); } else { if(L+mid+1<=R) { flag = true; //break; } L = INF; R = -INF; } } if(L+mid+1<=R) flag = true; if(flag) l = mid + 1; else r = mid - 1; } if(l>=5) printf("%d\n",l); else puts("0"); } return 0; }