hdu6231 K-th Number 二分,尺取

有一个长度为n的序列n<=1e5
每次把长度大于等于k的区间的第k大的数
放在b数列中,问b数列当中的第m大的数是什么
首先:答案是第m大的数,那么说明b数列中大于
等于该答案的数都是从区间中取出来的,而且取了
m个,而比答案小的数的话,那么大于等于该数的
取出的区间数目会大于m所以可以二分答案,对于当前
答案,算出有多少个区间的第k大的数(这个数还得比
当前二分的答案大),如果大于m说明较小,反之亦然。

#include <iostream>
#include <cstdio>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
using namespace std;
const int maxn=1e5+100;
int p[maxn],n,k;
ll m;
ll compute(int o);
int main()
{
    int t,ans,l,r,mid;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%lld",&n,&k,&m);
        rep(i,1,n) scanf("%d",&p[i]);
        l=1,r=1000000000;
        while(l<=r)
        {
            mid=(l+r)/2;
            if(compute(mid)>=m)
                l=mid+1,ans=mid;
            else
                r=mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
ll compute(int o)
{
    int i,j=1,num=0;
    ll s=0;
    for(i=1;i<=n;i++)
    {
        if(p[i]>=o) num++;
        if(num==k)
        {
            while(p[j]<o)
                s+=n-i+1,j++;
            s+=n-i+1;
            j++,num--;
        }
    }
    return s;
}
/*
有一个长度为n的序列n<=1e5
每次把长度大于等于k的区间的第k大的数
放在b数列中,问b数列当中的第m大的数是什么
首先:答案是第m大的数,那么说明b数列中大于
等于该答案的数都是从区间中取出来的,而且取了
m个,而比答案小的数的话,那么大于等于该数的
取出的区间数目会大于m所以可以二分答案,对于当前
答案,算出有多少个区间的第k大的数(这个数还得比
当前二分的答案大),如果大于m说明较小,反之亦然。
*/

猜你喜欢

转载自blog.csdn.net/hyacinthhome/article/details/81610166