• HDU


    题目链接:

    题意:

    给出一个长为N的序列,求出所有子序列中的第k大数(子序列长度必然大于等于k)并将其添加到一个新的序列中,求这个新序列的第m大为多少。

    思路:

    (本弱鸡打这场模拟赛时没有做出来,太惨了...)

    首先,看榜过的人不是很多,加上这种 求第k大的数(肯定不会用到 主席数,树状数组),因为求的是所有子区间,加上又有多组样例。所以我就一直想子区间之间的关系,一开始想既然是第 k 大,那么长度为 k的子区间,就是求其区间最小值(单调队列)。然后再 希望通过某种 递推关系 去一次推出区间长度+1 情况的第k大值。但是没有想出来这种思路的解法(可能方向都错了)。

    模拟赛打完后看了题解,觉得的确非常巧妙。题解是通过找到了 某个值 与第k大,以及与新形成序列 的m大 之间的关系,求得的。

    比如 对于下面样例序列(答案为3)

    5 3 2
    2 3 1 5 4

    首先我们知道最后新的序列组成 来源于原序列。我们对原序列排序 1 2 3 4 5 , 那么新序列的组成形式为 ( 1(a) , 2(b), 3(c) ,4 (d), 5(e) )//这里的a,b,c,d,e表示出现次数

    若原序列中,所有长度不小于k的连续子序列中,第k大数不小于x,的子序列一共有ans个,那么x在所有第k大元素组成的数列中的位置排在 ans 个之后了

    而对于 求解 ans个做法即时,首先找到一个区间从 l 开始第一个满足 x 为第 k 大的 r 位置(尺取法),然后对于其右边的长度部分 (n-r+1) , 如果有比 x 小,则对 x 排名没影响;

    比x大,x排名就降低(就统计排在第k大,并且大于x的区间数)。所以这样就求出了 所有第k大数不小于x的子序列个数(子区间)。由于尺取是 O(N)

    我们如果再遍历搜索就会到 O(N^2) , 所以我们再使用二分搜索 降到 O(N logN) 复杂度。

    code:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5+7;
    const int inf = 0x3f3f3f3f;
    
    ll a[maxn];
    ll b[maxn];
    ll n,k,m;
    
    bool judge(int x){
        int num=0,j=1;
        ll ans =0;
        int l=1,r=0;
    //    尺取法的两种写法
        while(r<=n){
            if(num<k){
                if(a[r+1]>=x) num++;
                r++;
            }else{
                if(num==k) ans += n-r+1;
                if(a[l]>=x) num--;
                l++;
            }
        }
    //    for(int i=1;i<=n;i++){
    //        if(a[i]>=x) num++;
    //        if(num==k){
    //            ans += n-i+1;
    //            while(a[j]<x){
    //                ans += n -i +1;
    //                j++;
    //            }
    //            num--;
    //            j++;
    //        }
    //    }
        //小于或者等于
        if(ans>=m) return true;
        //大于
        else return false;
    }
    int main(){
        int T;
        scanf("%d",&T);
        while(T--){
            scanf("%lld %lld %lld",&n,&k,&m);
            memset(b,0,sizeof(b));
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
                b[i] = a[i];
            }
            sort(b+1,b+1+n);
            int size = unique(b+1,b+1+n) - (b+1); 
            int l =1,r= size;
            while(l<=r){
                int mid = (l+r)>>1;
                if(judge(b[mid])){
                       l = mid+1;
                }else{
                    r = mid-1;
                }
            }
            printf("%d
    ",b[l-1]);    
        }
        return 0;
    }
  • 相关阅读:
    OLAP ODS项目的总结 平台选型,架构确定
    ORACLE ORA12520
    ORACLE管道函数
    ORACLE RAC JDBC 配置
    ORACLE RAC OCFS连接产生的错误
    ORACLE 启动和关闭详解
    OLAP ODS项目的总结 起步阶段
    ORACLE RAC 配置更改IP
    ORACLE RAC OCR cann't Access
    ORACLE RAC Debug 之路 CRS0184错误与CRS初始化
  • 原文地址:https://www.cnblogs.com/Tianwell/p/11514693.html
Copyright © 2020-2023  润新知