CF1712D Empty Graph 题解
题目大意
-
给定一个序列 $ a_1,a_2,\ldots,a_n $。
-
你可以进行最多 \(k\) 次操作,每次操作选定一个数字 \(i\)($ 1 \le i \le n $)和一个整数 \(x\) ($1 \le x \le 10^9 $),使 \(a_i=x\)。
-
建立一张有 \(n\) 个点的图,对每个点从 \(1\) 到 \(n\) 进行编号,其中点 \(l\) 和点 \(r\) 之间连有一条边权为 $\min(a_{l},a_{l+1},\ldots,a_{r}) $ 的边。
-
找出两点之间的最短路径的最大值。
思路
首先看到求最短路径的最大值,最小值最大,妥妥的二分答案。
根据题目中两个点之间连边的边权的性质,不难推断出最大值一定出现在相邻的两个点之间,不相邻的两个点之间可能存在更小的值,即使是有更大的值也不会成为边权。
两个点之间的最短路要么是两个点之间的边直达,要么是找一个最小的点,以最小的点作为中转站在两个点之间折跃,即点 \(l\) 和点 \(r\) 之间的最短路为 \(\min( \min(1,n)\times2,\min(l,r))\)。
在二分枚举答案时,假设当前枚举的答案为 \(pos\) ,可以考虑设一个前缀和和一个后缀和,统计 \(a_i\times2\le pos\) 的 \(i\) 的数量,因为每个 \(a_i\times2\le pos\) 的 \(i\) 即是我们需要修改的点。
我们从 \(1\) 到 \(n-1\) 枚举,统计最小的 \(pre_{i-1}+sub_{i+2}+ord(a_i<pos)+ord(a_{i+1}<pos)\),判断是否成立即可。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int t, n, k, a[100010], pre[100010], sub[100010];
bool check(int pos) {
for (int i = 1; i <= n; i++) {
pre[i] = pre[i - 1] + (int)((a[i] << 1) < pos);
}
for (int i = n; i; --i) {
sub[i] = sub[i + 1] + (int)((a[i] << 1) < pos);
}
int minx = 0x7fffffff;
for (int i = 1; i < n; i++) {
minx = min(minx, pre[i - 1] + sub[i + 2] + (int)(a[i] < pos) + (int)(a[i + 1] < pos));;
}
return minx <= k;
}
signed main() {
scanf("%lld", &t);
while (t--) {
scanf("%lld%lld", &n, &k);
memset(pre, 0, sizeof(pre));
memset(sub, 0, sizeof(sub));
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
int l = 0, r = 1e9, ans = 0;
while (l <= r) {
int mid = l + r >> 1;
if (check(mid)) {
l = mid + 1;
ans = mid;
} else {
r = mid - 1;
}
}
printf("%lld\n", ans);
}
return 0;
}

浙公网安备 33010602011771号