標籤:os for io amp ios algorithm
題目大意:
求可覆蓋的出現k次的子串的最大長度。
思路分析:
同樣是二分答案的長度,然後掃描height判斷是否成立。
#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#define maxn 1000005using namespace std;int str[maxn];int sa[maxn],t1[maxn],t2[maxn],c[maxn],n;void suffix(int m){ int *x=t1,*y=t2; for(int i=0;i<m;i++)c[i]=0; for(int i=0;i<n;i++)c[x[i]=str[i]]++; for(int i=1;i<m;i++)c[i]+=c[i-1]; for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1) { int p=0; for(int i=n-k;i<n;i++)y[p++]=i; for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k; for(int i=0;i<m;i++)c[i]=0; for(int i=0;i<n;i++)c[x[y[i]]]++; for(int i=0;i<m;i++)c[i]+=c[i-1]; for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1;x[sa[0]]=0; for(int i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; if(p>=n)break; m=p; }}int rank[maxn],height[maxn];void getheight(){ int k=0; for(int i=0;i<n;i++)rank[sa[i]]=i; for(int i=0;i<n;i++) { if(k)k--; if(!rank[i])continue; int j=sa[rank[i]-1]; while(str[i+k]==str[j+k])k++; height[rank[i]]=k; }}bool ok(int len,int k){ int cnt=1; for(int i=1;i<=n;i++) { if(height[i]<len) { cnt=1; } else { cnt++; if(cnt>=k)return true; } } return false;}int bin(int k){ int l=1,r=n,ans=0; while(l<=r) { int mid=(l+r)>>1; if(ok(mid,k)) { ans=mid,l=mid+1; } else r=mid-1; } return ans;}int main(){ int k; while(scanf("%d%d",&n,&k)!=EOF) { for(int i=0;i<n;i++) scanf("%d",&str[i]); str[n]=0; n++; suffix(256); getheight(); printf("%d\n",bin(k)); } return 0;}/*9 21 2 3 4 5 6 7 8 9*/