poj3261(后缀树组)
Milk Patterns
题意:
求给出的串中最少出现k次的最长可重复子串的长度。
分析:
既然要求长度,我们就二分这个长度,判断在这个长度下是否成立。首先根据给出的串求出height数组,根据height数组的性质,如果在len长度下,存在一个区间的数都大于等于len,且区间的长度大于等于k-1(因为k-1个height代表k个后缀),那么len就是一个可重复子串的长度,二分取最优解即可。
代码:
#include <map> #include <queue> #include <math.h> #include <string> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=1e6+100; int n,k; int r[maxn],sa[maxn],Rank[maxn],height[maxn]; namespace Suffix { int wa[maxn],wb[maxn],wv[maxn],wt[maxn]; int cmp(int *r,int a,int b,int k) { return r[a]==r[b]&&r[a+k]==r[b+k]; } 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++) wt[i]=0; for(i=0; i<=n; i++) wt[x[i]=r[i]]++; for(i=1; i<m; i++) wt[i]+=wt[i-1]; for(i=n; i>=0; i--) sa[--wt[x[i]]]=i; p=1; j=1; for(; p<=n; j*=2,m=p) { for(p=0,i=n+1-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++) wt[i]=0; for(i=0; i<=n; i++) wt[wv[i]]++; for(i=1; i<m; i++) wt[i]+=wt[i-1]; for(i=n; i>=0; i--) sa[--wt[wv[i]]]=y[i]; t=x; x=y; y=t; x[sa[0]]=0; for(p=1,i=1; i<=n; i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++; } } void getheight(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; i++) { if(k) k--; else k=0; j=sa[Rank[i]-1]; while(r[i+k]==r[j+k]) k++; height[Rank[i]-1]=k; } } }; bool check(int x) { int cnt=0; for(int i=1;i<n;i++){ if(height[i]>=x) cnt++; else cnt=0; if(cnt==k-1) return true; } return false; } int binary_Search() { int l=1,r=n; while(l<=r) { int mid=(l+r)>>1; if(check(mid)) l=mid+1; else r=mid-1; } return r; } int main() { // freopen("in.txt","r",stdin); while(scanf("%d %d",&n,&k)!=EOF) { int mx=-1; for(int i=0;i<n;i++){ scanf("%d",&r[i]); mx=max(mx,r[i]); } r[n]=0; Suffix::da(r,sa,n,mx+1); Suffix::getheight(r,sa,n); printf("%d\n",binary_Search()); } return 0; }