有n个数字,求有k个重复的最大长度(可重叠
先是WA,因为我就是把height数组从1开始扫了一遍,看是否大于或等于mid,如果是的话,就num++;这样的话,就不一定是同一个子串了,也就是说,我前几个最大前缀满足mid ,然后下一个不满足,然后下下个height【i】>=mid,这个时候就不是和前面同一个子串 了。所以是连续的height值。
然后改过了之后TLE。因为如果height[i]>=mid, 然后我就往后扫,然后找到一个不满足的,下一次我就从这个不满足的地方开始扫,而不是从第一个满足的后面开始扫。
然后过了,但是时间是200+ms,看了看别人都是100内,然后加了个离散化,终于79ms
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include<string>
using namespace std;
const int maxn =2e4+10;
int vis[maxn];
int q[maxn];
struct Suffix
{
int s[maxn];
int SA[maxn],ranked[maxn],height[maxn];
int x[maxn],y[maxn],buc[maxn],len,m;
void init(int *str,int lenn)
{
// len=strlen(str);
len=lenn;
for(int i=0;i<len;i++) s[i]=(int)str[i];
m=2e4+10;//
}
void GetSA()
{
for (int i = 0; i < m; i++)
buc[i] = 0; // buc 是一个桶
for (int i = 0; i < len; i++) buc[x[i] = s[i]]++;
for (int i = 1; i < m; i++)
buc[i] += buc[i - 1];
for (int i = len - 1; i >= 0; i--)
SA[--buc[x[i]]] = i;
for (int k = 1; k <= len; k <<= 1) { // k 倍增
int p = 0;
//对第二关键字排序,y[i]:第i大的第二关键字是谁
// 后缀 len - k 及之后的所有后缀第二关键字最小。为0
for (int i = len - 1; i >= len - k; i--)
y[p++] = i;
for (int i = 0; i < len; i++)
if (SA[i] >= k)
y[p++] = SA[i] - k;
//总体来排个序,求出SA
for (int i = 0; i < m; i++) buc[i] = 0;
for (int i = 0; i < len; i++)
buc[x[y[i]]]++;
for (int i = 1; i < m; i++)
buc[i] += buc[i - 1];
for (int i = len - 1; i >= 0; i--)
SA[--buc[x[y[i]]]] = y[i];
swap(x, y);
p = 1; x[SA[0]] = 0;
// 重新计算每个一元的名次。则x数组里存的是总体的顺序
for (int i = 1; i < len; i++) {
if (y[SA[i - 1]] == y[SA[i]] && y[SA[i - 1] + k] == y[SA[i] + k])
x[SA[i]] = p - 1;
else x[SA[i]] = p++;
}
if (p >= len) break; // 每个后缀的名次已经完全不同,不需要继续倍增
m = p; // 更新名次的最大值。
}
}
void Getheight()
{
for(int i=0;i<len;i++)
ranked[SA[i]]=i;
int k=0;
for(int i=0;i<len;i++)
{
if(ranked[i]==0) {height[0]=0;continue;}
if(k) k--;
int j=SA[ranked[i]-1];
while(s[i+k]==s[j+k]&&i+k<len&&j+k<len) k++;
height[ranked[i]]=k;
}
}
};
Suffix S;
int a[maxn];
int n,k;
int ok(int mid)
{
int i=1;
while(1)
{
int num=1;
for(;i<=n-k+1;i++)
{
if(S.height[i]>=mid)
{
break;
}
}
if(i>(n-k+1)) break;
for(;i<=n;i++)
{
if(S.height[i]>=mid) num++;
else break;
}
if(num>=k) return 1;
}
return 0;
}
int main()
{
scanf("%d %d",&n,&k);
for(int i=0;i<n;i++) {scanf("%d",&a[i]);q[i]=a[i];}
sort(q,q+n);
int nn=unique(q,q+n)-q;
for(int i=0;i<n;i++)
{
int gg=lower_bound(q,q+nn,a[i])-q;
a[i]=gg;
}
S.init(a,n);
S.GetSA();
S.Getheight();
int l=1,r=n,res=1;
while(l<=r)
{
int mid=l+(r-l)/2;
if(ok(mid)) {
res=mid;
l=mid+1;
}
else r=mid-1;
}
printf("%d\n",res);
return 0;
}