NC14301 K-th Number
K-th Number
https://ac.nowcoder.com/acm/problem/14301
题目大意
给定长为 的序列,求其所有长度
的子区间的第
大数,所构成多重集的第
大数。
题解
二分。
现判定 。问题转化为求第
大数
的子区间个数,若其
则判定失败,否则判定成功。
如果将原始序列转化为一个 01 序列,某位置上为 表示原始序列上这个位置的数
,否则为
,那么区间个数就等于为该 01 序列中子区间和
的区间个数。这个显然是可以用尺取法计算的。
#include <bits/stdc++.h>
#define INF 2000000000
using namespace std;
typedef long long ll;
int read(){
int f = 1, x = 0;
char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();}
while(c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
return f * x;
}
int n, k;
ll m;
int a[100005], b[100005];
void init(){
n = read(), k = read();
scanf("%lld", &m);
for (int i = 1; i <= n; ++i)
a[i] = read(), b[i] = a[i];
sort(b + 1, b + n + 1);
}
bool judge(int x){
ll res = 0;
for (int i = 1, cur = 0, cnt = 0; i <= n; ++i){
while (cur < n && cnt < k){
++cur;
if (a[cur] > x) ++cnt;
}
if (cur == n && cnt < k) break;
res += (n - cur + 1);
if (a[i] > x) --cnt;
}
return res < m;
}
void solve(){
int l = 1, r = n;
while (r > l){
int mid = (l + r) >> 1;
if (judge(b[mid]))
r = mid;
else l = mid + 1;
}
printf("%d\n", b[l]);
}
int main(){
int T = read();
while (T--){
init();
solve();
}
return 0;
} 小结
有的时候二分判定的不仅仅是一个答案,还可以是一个答案区间。
这个大部分时候都是显然的,但是有的时候会忽略。
海康威视公司福利 1137人发布