​hdu6231​

根本想不到啊…

题意

在所有区间长度大于 k k k的区间选出第 k k k大的数加入数组 b b b

问最后数组 b b b的第 m m m大

做法

枚举区间计算复杂度上天

但是可以二分计算答案

二分 m i d mid mid,假设最后的答案大于等于 m i d mid mid就返回 t r u e true true

怎么 c h e c k ? check? check?

二分之后,每个数要么大于等于 m i d mid mid,要小于 m i d mid mid

我们想求有多少区间的第 k k k大比 m i d mid mid大

维护 l , r l,r l,r指针尺取区间

如果 a i > = m i d a_i>=mid ai>=mid,计数器加一

当计数器到达 k k k时,说明包含当前区间的区间的第 k k k大一定大于等于 m i d mid mid

所以计算 a n s ans ans

这样通过尺取的手段,就得到了 a n s ans ans,也就是多少个区间的第 k k k大比 m i d mid mid还大

如果 a n s > = m ans>=m ans>=m,说明答案确实大于等于 m i d mid mid

否则,说明答案小于 m i d mid mid

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
int n,k,a[100009],m;
bool isok(int x)
{
int ans=0,num=0,j=1;
for(int i=1;i<=n;i++)
{
if( a[i]>=x ) num++;
if( num==k )//说明区间第k大是大于x的
{
ans+=n-i+1;//右端点的取值
while( a[j]<x )//移动左端点
ans+=n-i+1,j++;
num--,j++;
}
}
if( ans>=m ) return true;
return false;
}
signed main()
{
int t; cin >> t;
while( t-- )
{
cin >> n >> k >> m;
int l=1e9+1,r=0;
for(int i=1;i<=n;i++)
{
cin >> a[i];
l = min(l,a[i]);
r = max(r,a[i]);
}
int ans=0;
while( r>=l )
{
int mid = l+r>>1;
if( isok(mid) ) l=mid+1,ans=mid;
else r=mid-1;
}
cout << ans << '\n';
}
}