hdu6231 K-th Number(二分答案+尺取)

来源:互联网 发布:win7优化软件 编辑:程序博客网 时间:2024/05/17 02:28

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=6231

题意:

输入n,k,m,需要求在n个数的a数组中,任意区间里选择第k大的数存入b数组,在b数组中求得第m大的数

解:

其实一开始没懂怎么去解这道题,但可以反过来想想,如果我是b数组中一个数如何满足题目所要求的条件 ?

首先将a数组存入b数组,且将b数组排序,二分下标得到b[mid],判断b[mid]在a数组中的任意区间里有多少种情况存在那么一个第k大的数,

如果存在的情况大于m,那么该数偏小;若小于m,则该数偏大;

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>using namespace std;//先在b数组(b数组为a数组中的各项元素且排好序)中二分一个数x//将x放置在a中进行比较查找,找到第k大的数记录位置后,用n减去该下标//因为区间任意,所以k的可能性就有n-r的累加//最后结果如果比m大,那么该x偏小;如果比m小,那么该x偏大//结果与m比较的意义在于,k的存在数目比m大的话表明有足够的k拼凑出m;const int maxn = 1e5+20;typedef long long ll;ll a[maxn],b[maxn];ll k,m,n;ll judge(ll x){    ll num=0;    ll l=1,r=0;    ll sum=0;    while(r<=n)    {        if(num<k)        {           if(a[r+1]>=x)num++;           r++;        }        else        {            if(num==k)sum+=n-r+1;            if(a[l]>=x)num--;            l++;        }    }    return sum;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%I64d%I64d%I64d",&n,&k,&m);        for(int i=1;i<=n;i++)        {scanf("%I64d",&a[i]);b[i]=a[i];}        sort(b+1,b+1+n);        int l=1,r=n;ll ans=0;        int mid;        //cout<<"1"<<endl;        while(r>=l)        {            mid=(r+l)/2;            //cout<<"3"<<endl;            if(judge(b[mid])>=m)            {                ans=b[mid];                l=mid+1;            }            else            r=mid-1;        }        //cout<<"2"<<endl;        printf("%I64d\n",ans);    }    return 0;}


原创粉丝点击