题目传送门
在牛客的寒假算法训练营1中,炸鸡块君出了一个题对于中位数的结论在这里的体现也是非常恰当的:
记数列中≥ 𝒎的数字有𝒄𝒏𝒕𝟏个,< 𝒎的数字有𝒄𝒏𝒕𝟐个,则答案为
𝒄𝒏𝒕𝟏 − 𝒄𝒏𝒕𝟐,该值≤ 𝟎时则不存在答案。
那么分析这道题,我们要求
[
l
,
r
]
[l,r]
[l,r]数的个数大于非
[
l
,
r
]
[l,r]
[l,r]内的数的个数。
那么我们怎么进行问题的转化呢?
原问题其实就是让求
(
−
∞
,
m
)
(-∞,m)
(−∞,m)的个数小于
[
m
,
+
∞
)
[m,+∞)
[m,+∞)的个数,和本问题非常类似,那么我们只需要求出来在区间内的数的个数有𝒄𝒏𝒕𝟏个,不在区间内的数的个数有𝒄𝒏𝒕𝟐个,用二分/双指针找到𝒄𝒏𝒕𝟏 − 𝒄𝒏𝒕𝟐=k的
l
,
r
l,r
l,r就可以。
然后模拟一遍就没问题了。
#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define endl '\n'
typedef pair<int,int>pii;
int n,k;
int o=0;
int a[210210];
int b[210210];
void solve(){
cin>>n>>k;
memset(b,0,(sizeof (int)*(n+1)));
for(int i=1;i<=n;i++){
cin>>a[i];
b[a[i]]++;
}
for(int i=1;i<=n;i++){
b[i]+=b[i-1];
}
int l,r;
int minn=1e9;
for(int i=1,j=1;i<=n;i++){
while(j<=n&&((b[j]-b[i-1])-(n-(b[j]-b[i-1])))<k)j++;
if(j>n)j--;
if((minn>j-i)&&((b[j]-b[i-1])-(n-(b[j]-b[i-1])))>=k){
minn=j-i;l=i,r=j;
}
}
cout<<l<<" "<<r<<endl;
int last=1;
while(k){
if(k==1){
cout<<last<<" "<<n<<endl;
break;
}
int yes=0,no=0;
for(int i=last;i<=n;i++){
if(a[i]>=l&&a[i]<=r)yes++;
else no++;
if(yes>no){
k--;
cout<<last<<" "<<i<<endl;
last=i+1;
break;
}
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
}