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的主要内容,如果未能解决你的问题,请参考以下文章

K-th Number POJ - 2104 (整体二分)

POJ 2104 K-th Number 主席树模板题

SP3946 MKTHNUM - K-th Number(整体二分)

POJ2104 K-th Number(整体二分)

POJ-2104 K-th Number CDQ分治

POJ2104 K-th Number 静态区间第k最值 平方分割