K-th Number

一、题意描述

对数列A的每个区间求第K大,并将第K大插入到B中,再求B中的第M大。

输入描述: The first line is the number of test cases.For each test case,the first line contains three positive numbers N(1 ≤ N ≤ 10^5);K(1 ≤ K ≤ N);M.

The second line contains N numbers Ai(1 ≤ Ai ≤ 10^9).

It's guaranteed that M is not greater than the length of the array B.

输出描述:

For each test case,output a single line containing the M-th largest element in the array B.

二、题意分析

首先先理解该题意,题目的意思其实是从A中的某一区间取出在该区间中第K大的数,并将其插入到B中,当A中长度不足K时,此时就不再插入,求B中第M大的元素.先说说我对这道题的思考吧,其实刚开始我自己写这道题的时候,可能是由于还没太理解这道题的题意吧,就导致刚开始雨巨讲这道题的时候没太理解,但是后来随着自己不断重现雨巨的思路,其实慢慢地就逐渐理解了这道题,可能这就是“由果溯因”吧.

对于这道题,肯定暴力枚举这个方法咱们都能想到,但是这肯定会卡我们的时间复杂度,那么我们就得换一个思路.咱们再仔细分析该题,发现其答案具有单调性,当我们二分出来的答案 <= 真实答案,此时说明咱们可以继续往大了二分,即l = mid - 1;而当我们二分出来的答案 > 真实答案时,此时说明我们需要往小了二分,即r = mid - 1;那么二分验证的思路又是什么呢?

首先我们思考我们二分的答案是序列B中的第M大,而这个数又是拿出部分数后的序列A中的第K大数,那么其实想到这里思路其实已经出来了.我们需要从A中拿出M个数,而这M个数中每次从区间取出来的时候都是其区间的第K大,那么其实该验证思路已经转换成A中第K大数大于等于x的区间总数要大于等于M个.再想明白这点之后,其实后续也就简单了,后续我们只需要该区间个数是多少就行了,也就需要注意一下尺取法的一个易错点.我们枚举区间的左端点L,然后去枚举右端点R.根据题意的特点,可以采取尺取进行优化.

时间复杂的分析:二分的时间复杂度为O(logn),而验证的时间复杂度是O(n),所以综上该程序总的时间复杂度为O(nlogn).

三、代码分析

当上面思路想清楚以后,其实AC代码就呼之欲出了,AC代码如下:

using namespace std;

typedef long long ll; //注意不要超出数据范围
int t,n,k,a[100010];
ll m;
bool judge(int x){
    ll cnt = 0,ans = 0;
    int l = 1,r = 1;
    for (;l <= n;l++){
        if (a[l - 1] >= x) cnt--;
        for (;r <= n;r++){
            if (a[r] >= x) cnt++;
            if (cnt >= k){
                ans += (n - r + 1);
                if (a[r] >= x) cnt--; //此时要注意,进入该条判断语句后,break掉之后r不会继续++,下次循环有可能会使得cnt重复++
                break;
            }
        }
    }
    return ans >= m;
}
int main(){
    scanf("%d",&t);
    while (t--){
        scanf("%d%d%lld",&n,&k,&m);
        int l = 1,r = 0;
        for (int i = 1;i <= n;i++){
            scanf("%d",&a[i]);
            r = max(r,a[i]);
        }
        while (l <= r){
            int mid = (l + r) >> 1;
            if (judge(mid)) l = mid + 1;
            else r = mid - 1;
        }
        cout << l - 1 << endl;
    }
    return 0;
}

四、个人总结

其实以后主要还是要先理解题意,得把题意理解清楚,如此方能进行下一步的求解.总的来说,该题其实是一个比较好的二分、分治的题.也需要我不断回顾该题.

全部评论

相关推荐

工作基本定了,比较满意。这深度学习真是难搞啊,论文看不懂,代码看不懂,不会改,创新点???&nbsp;还有一个月中期,怎么搞,已经抑郁了,没有小论文要求,我真是非常幸运了,不然就我这科研能力…………&nbsp;感觉自己对自己失去信心,无时无刻不在否定自己取得一些成绩都是运气好罢了,真的能顺利毕业吗?严重内耗、无力感爆棚啊…………
AI牛可乐:哎呀,听起来你最近压力好大呀,毕业论文和工作的双重压力一定让你感觉像是背了两座山呢。深度学习确实挺复杂的,就像是要在一片迷雾中找到出路一样。但是,你已经很棒了,工作都定好了,这是很大的成就呢! 论文的事情,别太担心。每个人都有看不懂代码和论文的时候,这是正常的。至于创新点嘛,有时候灵感就像小猫一样,需要一点一点地哄出来的。你可以先试试把你看过的资料整理一下,说不定就能找到新的思路呢。 中期答辩前,你可以列个计划,一步一步来,把大问题分解成小问题,一点一点克服。记得,你不是一个人在战斗,你的导师、同学都是你的战友哦。 至于信心嘛,别否定自己,每个人都会有低谷的时候。你已经取得的成绩,都是你实力的体现。毕业不是问题,只要你不放弃,就一定能顺利走过去的。加油哦,我相信你可以的! 对了,如果你愿意的话,可以点击我的头像,我们私信聊,也许我能帮你出出主意,或者就是简单地聊聊天,分散一下你的注意力也好呀。🐮💪🌟
点赞 评论 收藏
分享
jack_miller:我给我们导员说我不在这里转正,可能没三方签了。导员说没事学校催的时候帮我想办法应付一下
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务