【算法】后缀数组
【题解】后缀数组
由于m太大,先离散化。
然后处理SA和LCP。
最后用单调队列处理即可。
注意实际上队列头尾长度限制是K-1.
删队尾不要删过头
i≥K才能开始统计答案。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=20010; int n,m,s[maxn],x[maxn],y[maxn],base[maxn],sa[maxn],h[maxn],K,q[maxn]; struct lshs{int ord,num;}lsh[maxn]; bool cmp(lshs a,lshs b) {return a.num<b.num;} void build_sa(int m) { for(int i=1;i<=m;i++)base[i]=0; for(int i=1;i<=n;i++)base[x[i]=s[i]]++; for(int i=2;i<=m;i++)base[i]+=base[i-1]; for(int i=n;i>=1;i--)sa[base[x[i]]--]=i; for(int k=1;k<=n;k<<=1) { int p=0; for(int i=n-k+1;i<=n;i++)y[++p]=i; for(int i=1;i<=n;i++)if(sa[i]>k)y[++p]=sa[i]-k; for(int i=1;i<=m;i++)base[i]=0; for(int i=1;i<=n;i++)base[x[i]]++; for(int i=2;i<=m;i++)base[i]+=base[i-1]; for(int i=n;i>=1;i--)sa[base[x[y[i]]]--]=y[i]; swap(x,y); p=1;x[sa[1]]=1; for(int i=2;i<=n;i++) x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p; if(p>=n)break; m=p; } int k=0; for(int i=1;i<=n;i++) { if(k)k--; int j=sa[x[i]-1]; while(s[i+k]==s[j+k])k++; h[x[i]]=k; } } int main() { scanf("%d%d",&n,&K); for(int i=1;i<=n;i++) { scanf("%d",&lsh[i].num); lsh[i].ord=i; } sort(lsh+1,lsh+n+1,cmp); int p=1;s[lsh[1].ord]=1; for(int i=2;i<=n;i++)s[lsh[i].ord]=lsh[i].num==lsh[i-1].num?p:++p; build_sa(p); K--; int head=0,tail=0; int ans=0; for(int i=2;i<=n;i++) { while(h[q[tail-1]]>h[i]&&tail>head)tail--; q[tail++]=i; if(i-q[head]>=K)head++; if(i>=K+1)ans=max(ans,h[q[head]]); } printf("%d",ans); return 0; }
时间: 2024-10-14 14:11:23