题意:
给定一个有n个整数的数组a,找到一个范围为[x,y] (x≤y)的值,并将a精确地分割成k个(1≤k≤n)子数组,如下所示:
(1)每个子数组由a的几个连续元素组成,即对于某l和r(1≤l≤r≤n),它等于al,al+1,…,ar。
(2)a中的每个元素都属于一个子数组。
(3)在每个子数组中,范围[x,y] (包括) 内的元素数量严格大于范围外的元素数量。当且仅当x≤ai≤y时,索引为i的元素在[x,y]范围内。
打印任何最小化y−x的解。
思路:
利用尺取法查找最小[x,y]并且满足k个区间。最后遍历数组。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e5+5;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;cin>>t;
while(t--){
int n,k;cin>>n>>k;
vector<int>cnt(n+1,0),arr(n+1,0);
for(int i=1;i<=n;i++){
cin>>arr[i];
cnt[arr[i]]++;
}
int x=0,y=INT_MAX;
int sum=0;//[x,y]范围内元素的个数
for(int l=1,r=1;l<=n;l++){
/*
n-sum表示不在[x,y]范围内的元素个数
sum-(n-sum)表示[x,y]范围内的元素个数和不在[x,y]范围的个数差大于k(说明可以组合k个区间)
sum-(n-sum)=2*sum-n
*/
while(r<=n&&2*sum-n<k){
sum+=cnt[r++];
}
if(2*sum-n>=k){
if(r-l<y-x+1){
x=l;
y=r-1;
}
}
sum-=cnt[l];
}
cout<<x<<" "<<y<<endl;
sum=0;//此时sum表示[l,r]的[x,y]范围内的元素个数
int last=0;
//需要留一个收尾(题目要是arr中的每个元素都要在子数组中)
for(int i=1;i<=n&&k>1;i++){
sum+=((arr[i]>=x&&arr[i]<=y)?1:-1);
if(sum>0){
cout<<last+1<<" "<<i<<endl;
last=i;
sum=0;
k--;
}
}
cout<<last+1<<" "<<n<<endl;
}
return 0;
}