题意
给一个长度为 的数组
,把所有长度大于等于
的区间中的第
大值插入
数组中, 问
数组的第
大数是多少
Solution
思路还是挺好想的, 但是实现起来感觉有点难度
因为求的是 数组的第
大, 但是
数组是由
数组中得来的
那么我们要求的答案肯定是在a数组中出现过啦
考虑把a数组中的数字排序后去重, 二分一下我们要的最终答案
二分的时候怎么去check呢
我们要check的思路是能否找到满足条件的区间总数大于等于
那么如何处理满足条件的区间总数呢?
我们考虑二分答案x, 那么在一段区间里, 统计大于等于x的数
当大于等于 的数超过
时, 证明这个区间可以取到第
大的数
, 使得
此时, 后面所延续的区间都是可选的区间
即 都满足要求
总共有个区间
这还没完!
考虑一下, 如果 这个数它小于我们二分的答案
, 那么他的作用形同虚设
这时候我们考虑 同样也是可行方案, 总共有
个
这还没完! * 2
如果 也小于呢!? 那又是重复上述的步骤!
我们重复这个操作, 直到出现 此时去掉它就满足不了
的约束啦
那么就往前尺取, 统计总的区间数是否大于等于
Code
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long long LL; const int N = 5e6 + 5; const ll mod = 1e9 + 7; const int DEG = 30; const double PI = acos(-1.0); const double eps = 1e-12; const ll inf = 1e18; static auto faster_iostream = []() { std::ios::sync_with_stdio(false); // turn off sync std::cin.tie(nullptr); // untie in/out streams return 0; }(); int a[N], b[N]; ll check(int x, int n, int k){ int cnt = 0; int pos = 1; ll ans = 0; for(int i = 1; i <= n; i++){ if(a[i] >= x){ cnt++; } if(cnt == k){ ans += n - i + 1; while(a[pos] < x){ // 重复这个步骤 ans += n - i + 1; pos++; } cnt--, pos++; } } return ans; } int main(){ int t; cin >> t; while(t--){ ll n, m, k; cin >> n >> k >> m; for(int i = 1; i <= n; i++) cin >> a[i], b[i] = a[i]; sort(b + 1, b + 1 + n); int len = unique(b + 1, b + 1 + n) - b - 1; int l = 1, r = len; int ans = 1; while(l <= r){ int mid = l + r >> 1; ll pos = check(b[mid], n, k); if(pos < m) r = mid - 1; else l = mid + 1, ans = mid; } cout << b[ans] << "\n"; } return 0; }