题目链接
题意:
给你一个序列,从这个序列中找一段顺序子序列(元素在子序列中的先后关系和在原序列中一致),定义一个g,g=min(max(子序列中下标为奇数的元素),max(子序列中下标为偶数的元素)),找出g的最小值。
思路:不难看出这是个二分的题,关键是check函数怎么写,分析式子我们可以发现要让式子成立只需要让子序列中下标为奇数元素最大值或下标为偶数元素最大值不大于g即可,换句话说只需要在原序列中找出一段不连续的且值不大于g的序列,再判断长度即可。
ac代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define int long long
int cnt[200005];
int ret[200005];
int n, k;
bool check(int a) {
int f = 0; int sum = 0;
int flag1 = 0, flag2 = 0;
for (int i = 1; i <= n; i++) {//(当所取之数在s序列中下标为奇数时)
if (f) {
sum++;
f--;
}
else {
if (ret[i] <= a) {
sum++;
f++;
}
}
}
if (sum >= k) flag1 = 1;
f = 1; sum = 0;
for (int i = 1; i <= n; i++) {//(当所取之数在s序列中下标为偶数时)
if (f) {
sum++;
f--;
}
else {
if (ret[i] <= a) {
sum++;
f++;
}
}
}
if (sum >= k) flag2 = 1;
if (flag1 == 1 || flag2 == 1) return true;//任意一种情况成立皆可
else return false;
}
signed main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> cnt[i];
ret[i] = cnt[i];
}
sort(cnt + 1, cnt + n + 1);
int l = 1, r = n;
int ans;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(cnt[mid])) {
ans = cnt[mid]; r = mid - 1;
}
else l = mid + 1;
}
cout << ans << endl;
}