この質問は、基本的に昨日書いた音楽のテーマと同じです。そのブログにはサフィックス配列の調査があります。以前にその質問を書いたことがない場合は、終了後に行うことができます。
題名
明らかに、最も長い繰り返し可能なサブストリングの長さを見つけることですが、サブストリングの繰り返しの数はK以上でなければなりません。
アイデア
Luo Suiqian「サフィックス配列-文字列を処理するための強力なツール」
は、最初にサフィックスツリーグループを検索し、次にサフィックスツリーグループを使用して高さ配列を検索します(height [i]:iおよびi-1にランク付けされたサフィックスサブストリングの最長の繰り返しプレフィックスを格納しますサブストリングの長さ)。ソートされたサフィックスをいくつかのグループに分割します。各グループのサフィックス間の高さの値はk以上です。たとえば、文字列は「aabaaaab」で、k = 2の場合、サフィックスは図に示すように4つのグループに分割されます。
グループ内の高さがk以上の場合、グループに含まれるサフィックス配列の数を判断するだけでよいと考えることができます。K以上で十分かどうか、満たすと長さがkに等しい場合も条件が満たされるので、長さを2つに分割して実行可能かどうかを判断する必要があります。
コード
#pragma GCC optimize(2)
//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
typedef unsigned long ul;
typedef unsigned long long ull;
#define pi acos(-1.0)
#define e exp(1.0)
#define pb push_back
#define mk make_pair
#define fir first
#define sec second
#define scf scanf
#define prf printf
typedef pair<ll,ll> pa;
const ll INF=0x3f3f3f3f3f3f3f3f;
const ll maxn=2e4+7;
const ll maxnum=1e6+7;
ll N,M,K;
ll sa[maxn],rank[maxn],r[maxn],height[maxn],tmp[maxn];
bool cmp(ll i,ll j){
if(rank[i]!=rank[j])
return rank[i]<rank[j];
ll r1=i+K<=N?rank[i+K]:-1;
ll r2=j+K<=N?rank[j+K]:-1;
return r1<r2;
}
//求后缀数组
void do_sa(){
ll i,j;
for(i=0;i<=N;i++){
sa[i]=i;
rank[sa[i]]=(i!=N?r[i]:-1);
}
for(K=1;K<=N;K<<=1){
sort(sa,sa+1+N,cmp);
tmp[sa[0]]=0;
for(i=1;i<=N;i++)
tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i])?1:0);
for(i=0;i<=N;i++)
rank[i]=tmp[i];
}
return ;
}
void get_height(){
ll i,j,k=0;
//枚举每个后缀的起始位置
for(i=0;i<N;i++){
if(k)
k--;
else
k=0;
j=sa[rank[i]-1];
while(r[i+k]==r[j+k])
k++;
height[rank[i]]=k;//height[i]:存储排名为i和i-1的后缀子串的最长前缀子串长度
}
return ;
}
bool check(ll mid){
ll i,j,cnt=0;
for(i=1;i<=N;i++){
if(height[i]>=mid){
cnt++;
if(cnt+1>=M)
return true;
}
else
cnt=0;
}
return false;
}
int main()
{
// freopen(".../.txt","w",stdout);
// freopen(".../.txt","r",stdin);
ios::sync_with_stdio(false);
ll i,j,k;
cin>>N>>M;
for(i=0;i<N;i++)
cin>>r[i];
do_sa();
get_height();
ll L=0,R=N,mid,res=0;
while(L<=R){
mid=(R-L)/2+L;
if(check(mid)){
L=mid+1;
res=max(res,mid);
}
else{
R=mid-1;
}
}
cout<<res<<endl;
return 0;
}