题面:
一句话题意:找一个闭区间 [x,y] ,把数组a分成k段子串,每段子串中在区间 [x,y] 范围内的ai的个数严格大于在区间 [x,y] 范围之外的数的个数。
我们可以知道,k个段内 xy区间内的数的个数 至少 比区间外数的个数大1,于是可以证明只要在数组a内 num(区间xy内的数) >= num(区间xy外的数)+k,则 无论数组怎样排列都可以有合理的划分。
接下来我们希望在至少nlogn时间复杂度内查找到一对差最小的xy使题意成立,这里我用的方法是维护两个指针xy,初始时使它们都等于0,每对xy统计在区间xy内数的个数是否满足条件:不满足条件则y++,增长区间;满足条件则x++,缩短区间找到xy差的最小值。
以下是代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int a[N],cnt[N];
int xa,ya;
int main(){
int t;cin>>t;
int n,k,x,y,num,d,mind;
while(t--){
memset(cnt,0,sizeof cnt);
cin>>n>>k;
x=0;y=0;
for(int i=0;i<n;++i){
cin>>a[i];
cnt[a[i]]++;
}
num=0;mind=N;d=0;//查找[x,y)最短区间,最终输出(x,y-1),查找方法类似滑窗
while(y<=n){
if(num-(n-num)<k){
num+=cnt[y];
y++;
}else{
if(d<mind){
mind=d;
xa=x;ya=y;
}
num-=cnt[x];x++;
}
d=y-x;
}
while(num-(n-num)>=k){
if(d<mind){
mind=d;
xa=x;ya=y;
}
num-=cnt[x];x++;
d=y-x;
}
ya=ya-1;
cout<<xa<<" "<<ya<<endl;//第一个输出
int i=0,j=0;num=0;//接下来划分数组a,
int nnn=0;
for(j;j<n;++j){
if(a[j]<=ya&&a[j]>=xa){
num++;
}else{
num--;
}
if(num==1){// 满足xy内的数个数比xy外数的个数多1就输出
num=0;
if(nnn==k-1){//最后一个划分结尾是n
cout<<i+1<<" "<<n<<endl;
break;
}else{//前n-1个划分
cout<<i+1<<" "<<j+1<<endl;
nnn++;
}
i=j+1;
}
}
}
}