#字尾陣列,單調佇列#洛谷 2852 [USACO06DEC]Milk Patterns G
阿新 • • 發佈:2020-11-03
題目
給定一個長度為\(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); }