K-th Number
Posted 吃花椒的妙酱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了K-th Number相关的知识,希望对你有一定的参考价值。
传送门
题目大意:将A数组中所有区间第k大的数,放入B数组中,求B数组中第M大的数
思路:二分答案+尺取检验
暴力n^2铁tle
我们直接假设答案,验证假设的数是否是第M大
我们先转化一下题目所求,设x,我们去求x是B中第几大,即求A数组中大于等于x的数至少有k个的区间有多少个
举个例子A数组1,2,3,4 k=2 m=3 设x=2
我们去看x=2是B中第几大,即求A中至少有2个数大于等于2的区间有多少个,如果比m大,说明x小了,反之亦然(关于二分单调性,A中至少有2个数大于等于2的区间数,必定多于A中至少有2个数大于等于3的区间数,以此类推)
可以想,到最后若至少有2个数大于等于x的区间只有一个,那x必定是B中第一大的数,因为只有它满足,它肯定是最大的了
(这题二分还是很妙的)
再谈谈check怎么写
尺取检验,右指针j去找第一个满足至少有k个数大于x的位置,如果到n还找不到,就直接break了,找到了,那么对于j后面的所有位置都满足要求,直接答案累加 ans += n- j+1
所以左右指针都没必要左移,对于每个左指针i我们去找第一个满足要求的j即可
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(x,y) memset(x,y,sizeof(x))
#define all(v) v.begin() , v.end()
#define pb(v) push_back(v)
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define int long long
#define lson p*2,l,mid
#define rson p*2+1,mid+1,r
typedef long long ll;
const int N = 1e5+10;
int a[N];
int n,k,m;
bool check(int mid)
{
int temp=0;
ll ans=0;
int j=1;
int cnt=0;
for(int i=1 ;i<=n ;i++)
{
while( cnt < k && j <= n)//找第一个满足有k个大于mid的区间
{
if( a[j]>=mid) cnt++;
j++;
}
if( cnt < k ) break;//如果找不到对于左指针i的第一个匹配的右指针,break
ans += n - (j-1) + 1;//找到的话,j后面所有的位置也必满足,直接累加
if( a[i]>=mid ) cnt--;//左指针右移,看之前i的位置是否≥mid
}
return ans >= m;//如果区间数大于m说明mid小了
}
void solve()
{
int l=1,r=1e9;
ll ans=0;
while( l<=r )
{
int mid = (l+r)>>1;
if( check(mid) ) l=mid+1;
else r=mid-1;
}
//l是mid的下界,即B数组中可能不止一个mid,l是mid的右区间
//r是最后一个满足check的数
cout<<r<<endl;
}
signed main()
{
//!!!!!!!!!!!!!!!!!!!!!!
// freopen("data.txt","r",stdin);
//!!!!!!!!!!!!!!!!!!!!!!
IOS;
int T;
cin>>T;
while( T-- )
{
cin>>n>>k>>m;
_for(i,1,n) cin>>a[i];
solve();
}
}
以上是关于K-th Number的主要内容,如果未能解决你的问题,请参考以下文章