#后缀数组,单调队列#洛谷 2852 [USACO06DEC]Milk Patterns G
题目
给定一个长度为\(n\)的字符串,求出现至少\(k\)次的最长子串长度
分析
由于后缀排序后的LCP才是最长的,既然要求至少\(k\)次,
实际上也就是维护长度为\(k\)的height数组最小值,可以用单调队列实现
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define rr register
using namespace std;
const int N=20011; int ans;
int C[N],sa[N],tp[N],rk[N],height[N],n;
int M,m,k,a[N],b[N],head,tail,q[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void SSort(){
for (rr int i=0;i<=M;++i) C[i]=0;
for (rr int i=1;i<=n;++i) ++C[rk[tp[i]]];
for (rr int i=1;i<=M;++i) C[i]+=C[i-1];
for (rr int i=n;i;--i) sa[C[rk[tp[i]]]--]=tp[i];
}
inline void Suffix_Array(){
for (rr int i=1;i<=n;++i) rk[i]=a[i],tp[i]=i;
M=m; SSort();
for (rr int len=1,p=1;p<n;M=p,len<<=1){
p=0;
for (rr int i=n-len+1;i<=n;++i) tp[++p]=i;
for (rr int i=1;i<=n;++i) if (sa[i]>len) tp[++p]=sa[i]-len;
SSort(),swap(tp,rk),rk[sa[1]]=p=1;
for (rr int i=2;i<=n;++i) rk[sa[i]]=(p+=tp[sa[i]]!=tp[sa[i-1]]||tp[sa[i]+len]!=tp[sa[i-1]+len]);
}
rr int j=0,k;
for (rr int i=1;i<=n;height[rk[i]]=j,++i)
for (j=j+!j-1,k=sa[rk[i]-1];a[i+j]==a[j+k];++j);
}
signed main(){
n=iut(),k=iut();
for (rr int i=1;i<=n;++i) b[i]=a[i]=iut();
sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1;
for (rr int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+m,a[i])-b;
Suffix_Array(),head=1;
for (rr int i=1;i<=n;++i){
while (head<=tail&&q[head]<=i-k+1) ++head;
while (head<=tail&&height[q[tail]]>=height[i]) --tail; q[++tail]=i;
if (i>=k-1&&head<=tail) ans=max(ans,height[q[head]]);
}
return !printf("%d",ans);
}