其他分享
首页 > 其他分享> > NC14301 K-th Number

NC14301 K-th Number

作者:互联网

NC14301 K-th Number

题目

题目描述

Alice are given an array A[1..N] with N numbers.
Now Alice want to build an array B by a parameter K as following rules:
Initially, the array B is empty. Consider each interval in array A. If the length of this interval is less than K, then ignore this interval. Otherwise, find the K-th largest number in this interval and add this number into array B.
In fact Alice doesn't care each element in the array B. She only wants to know the M-th largest element in the array B. Please help her to fi nd this number.

输入描述

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 \(A_i(1≤A_i≤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.

示例1

输入

2
5 3 2
2 3 1 5 4
3 3 1
5 8 2

输出

3
2

题解

思路

知识点:二分。

二分 \(B\) 的第 \(m\) 大,其在 \(B\) 序列中的位置具有单调性,检验大于等于这个数的 \(A\) 中所以子区间第 \(k\) 大的数量,如果数量大于等于 \(m\) ,说明这个数小于等于答案;反之,肯定大于。

计算大于等于这个数的 \(A\) 中所以子区间第 \(k\) 大的数量,通过对 \(A\) 尺取法快速计算区间总数,得到这个数在 \(B\) 中的排位。

注意的是,对答案二分时,不需要严格要求 \(mid\) 是在数组中的数,因为 \(l\) 和 \(r\) 最终会收敛到一个分界点上,而分界点只可能出现在数组中的数,所以不必担心。

坑点是 \(B\) 数组的长度是会超 \(int\) 的,因此 \(m\) 也会超 \(int\) 而题目没给范围,是最坑的。

时间复杂度 \(O(n \log n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int n, k;
ll m;///可能到 1e10,坑死了
int a[100007];

bool check(int mid) {/// 查询大于等于mid的第k大的数的数量是否大于等于m
    ll sum = 0;
    int i = 0, j = 0, cnt = 0;
    while (i < n) {
        while (j < n && cnt < k) {
            if (a[j] >= mid) cnt++;
            j++;
        }
        if (cnt == k) sum += n - j + 1;
        if (a[i] >= mid) cnt--;
        i++;
    }
    return sum >= m;
}

bool solve() {
    cin >> n >> k >> m;
    for (int i = 0;i < n;i++) cin >> a[i];
    int l = 1, r = 1e9;///不必担心mid不是数组中的数,因为最后收敛点一定在数组的某个数上
    while (l <= r) {
        int mid = l + r >> 1;
        if (check(mid)) l = mid + 1; ///check为真说明 mid 小于等于答案
        else r = mid - 1;
    }
    cout << r << '\n';///返回比最后一次小于等于答案的数的位置
    return true;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << '\n';
    }
    return 0;
}

标签:cnt,int,Number,mid,NC14301,th,each,array
来源: https://www.cnblogs.com/BlankYang/p/16420703.html