POJ 3261 Milk Patterns(后缀数组+单调队列)
题意
找出出现k次的可重叠的最长子串的长度
题解
用后缀数组。
然后求出heigth数组。
跑单调队列就行了。找出每k个数中最小的数的最大值。就是个滑动窗口啊
(不知道为什么有人写二分,其实写啥都差不多快,可能是因为二分是一个常见的模型吧)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const int N=1000100; 8 int n,m,x[N],sa[N],c[N],k,height[N],rk[N],y[N],ans,q[N],head,tail,s[N]; 9 void get_sa(){ 10 for(int i=1;i<=n;i++)c[x[i]=s[i]]++; 11 for(int i=1;i<=m;i++)c[i]+=c[i-1]; 12 for(int i=n;i>=1;i--)sa[c[x[i]]--]=i; 13 for(int k=1;k<=n;k<<=1){ 14 int num=0; 15 for(int i=n-k+1;i<=n;i++)y[++num]=i; 16 for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k; 17 for(int i=1;i<=m;i++)c[i]=0; 18 for(int i=1;i<=n;i++)c[x[i]]++; 19 for(int i=1;i<=m;i++)c[i]+=c[i-1]; 20 for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0; 21 for(int i=1;i<=n;i++){ 22 swap(x[i],y[i]); 23 } 24 x[sa[1]]=1;num=1; 25 for(int i=2;i<=n;i++){ 26 x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num; 27 } 28 if(n==num)break; 29 m=num; 30 } 31 } 32 void get_height(){ 33 for(int i=1;i<=n;i++)rk[sa[i]]=i; 34 int k=0; 35 for(int i=1;i<=n;i++){ 36 if(rk[i]==1)continue; 37 if(k)k--; 38 int j=sa[rk[i]-1]; 39 while(j+k<=n&&i+k<=n&&s[j+k]==s[i+k])k++; 40 height[rk[i]]=k; 41 } 42 } 43 int main(){ 44 scanf("%d%d",&n,&k); 45 if(k==1){ 46 printf("%d",n); 47 return 0; 48 } 49 m=1000005; 50 for(int i=1;i<=n;i++){ 51 scanf("%d",&s[i]); 52 } 53 get_sa(); 54 get_height(); 55 head=1;tail=0; 56 for(int i=2;i<=k;i++){ 57 while(height[i]<=height[q[tail]]&&head<=tail)tail--; 58 q[++tail]=i; 59 } 60 ans=height[q[head]]; 61 for(int i=k+1;i<=n;i++){ 62 while(q[head]<=i-k+1&&head<=tail)head++; 63 while(height[i]<=height[q[tail]]&&head<=tail)tail--; 64 q[++tail]=i; 65 ans=max(ans,height[q[head]]); 66 } 67 printf("%d",ans); 68 return 0; 69 }