后缀数组搞一下就可以了喵~
其实这道题的第一个想法是 SAM ,建完后缀自动机后拓扑排序跑一遍统计下每个子串的出现次数就 O(N) 就妥妥过掉了
后缀树也是 O(N) 的,统计一下每个节点对应的子树中有多少个叶子节点即可
可是看了一下数据范围,欸呦你妹啊,字符数 1000000+1 是什么心态啊!居然把我的后缀树和后缀 zdj 都卡掉了啊!
然后很痛苦的想了想后缀数组的做法:
搞出 sa, rank, height 三个数组后,跑一遍二分,用一个 tot 表示找到了几个子串
二分答案 L,O(N) 扫个遍如果 height[i]>=L 说明又找到一个子串,tot++,否则重新计算
不过注意这里 tot 的初始值是 1 而不是 0
不过这么个写法怎么写都是 O(NlogN) 的了,如果有更好的写法,请教我做人喵~
#include <cstdio> #include <cstring> const int sizeOfN=20002; const int sizeOfType=1200021; namespace IOspace { inline int getint() { register int num=0; register char ch; do ch=getchar(); while (ch<'0' || ch>'9'); do num=num*10+ch-'0', ch=getchar(); while (ch>='0' && ch<='9'); return num; } inline void putint(int num) { char stack[15]; register int top=0; if (num==0) stack[top=1]='0'; for ( ;num;num/=10) stack[++top]=num%10+'0'; for ( ;top;top--) putchar(stack[top]); putchar(' '); } } int N, K; int A[sizeOfN]; namespace suffixArray { int sa[sizeOfN], rank[sizeOfN], height[sizeOfN]; inline void swap(int *& x, int *& y) {int * t=x; x=y; y=t;} inline void buildArray() { static int t[2][sizeOfN]; static int c[sizeOfType]; int * x=t[0], * y=t[1]; int M=sizeOfType; for (int i=0;i<M;i++) c[i]=0; for (int i=0;i<N;i++) c[x[i]=A[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 j=0, k=1;j<N;M=j, k<<=1) { j=0; for (int i=N-k;i<N;i++) y[j++]=i; for (int i=0;i<N;i++) if (sa[i]>=k) y[j++]=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=1;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); j=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]?j-1:j++; } } inline void calcHeight() { int l=0; for (int i=0;i<N;i++) rank[sa[i]]=i; for (int i=0;i<N;i++) { int j=sa[rank[i]-1]; for (l=l?l-1:0;A[i+l]==A[j+l];l++); height[rank[i]]=l; } } } inline int search(); int main() { N=IOspace::getint(), K=IOspace::getint(); for (int i=0;i<N;i++) A[i]=IOspace::getint()+1; A[N++]=0; suffixArray::buildArray(); suffixArray::calcHeight(); IOspace::putint(search()); return 0; } inline bool check(int l) { int tot=1; for (int i=1;i<N;i++) if (suffixArray::height[i]>=l) { if (++tot>=K) return true; } else tot=1; return false; } inline int search() { int L=0, R=N, M; while (L+1<R) { M=(L+R)>>1; if (check(M)) L=M; else R=M; } return L; }
机房里把 插入代码(推荐) 给卡了真是 sang xin bing kuang!我要申诉!