专栏文章
题解:P8088 『JROI-5』Autumn
P8088题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mipfx1ao
- 此快照首次捕获于
- 2025/12/03 11:21 3 个月前
- 此快照最后确认于
- 2025/12/03 11:21 3 个月前
Solution
思路:二分答案。
问是哪来的?看看题,最小化最大值嘛!
不会有不会二分答案模板的吧?先上一个:
CPP问是哪来的?看看题,最小化最大值嘛!
不会有不会二分答案模板的吧?先上一个:
int l = 1, r = n, mid, ans;
while (l <= r) {
mid = (l + r) >> 1;
if (Check(mid)) {
ans = mid;
l = mid + 1; // 或 r = mid - 1
} else r = mid - 1; // 或 l = mid + 1
}
cout << ans << '\n';
但是,这里我们要的是数组中的值,而非 至 间任意值,所以我们需要一点修改——
CPP// num数组记录a数组中出现的数
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) num[++cnt] = a[i][j];
sort(num + 1, num + 1 + cnt);
cnt = unique(num + 1, num + 1 + cnt) - num;
// 进行二分
l = 1, r = cnt;
while (l <= r) {
mid = (l + r) >> 1;
if (Check(mid)) {
ans = mid;
r = mid - 1;
} else l = mid + 1;
}
cout << num[ans] << '\n';
OKOK,我们现在要的就是
将每一个数列(记为 )从大到小排序,则可将题转化为最小化 的最大值。
由于从大到小排序后期用 STL 不太方便,所以我们选择从小到大排序,然后最小化 的最大值。
设在某一方案中, 的最大值的最小值为 。
如果该方案可行,则对于每一个 , 及其之前的每一个数都应小于 。
如果有大于的怎么办?我们有 次的交换机会,将别的数列中多余的小于 的值换到这个序列来,以多补少。
假如够换,OK;假如不够换,那么退而求其次,看别的方案能不能行。这不就是二分的思想吗?
上
CPPCheck 函数了!将每一个数列(记为 )从大到小排序,则可将题转化为最小化 的最大值。
由于从大到小排序后期用 STL 不太方便,所以我们选择从小到大排序,然后最小化 的最大值。
设在某一方案中, 的最大值的最小值为 。
如果该方案可行,则对于每一个 , 及其之前的每一个数都应小于 。
如果有大于的怎么办?我们有 次的交换机会,将别的数列中多余的小于 的值换到这个序列来,以多补少。
假如够换,OK;假如不够换,那么退而求其次,看别的方案能不能行。这不就是二分的思想吗?
上
Check 代码:bool Check(int pos) {
int t = num[pos], lt = 0, gt = 0;
for (int i = 1; i <= n; i++) {
int p = upper_bound(a[i] + 1, a[i] + 1 + m, t) - a[i]; // 要事先将每条数列排序
if (k >= p) lt += k - p + 1;
else gt += p - k - 1;
}
if (lt <= gt && lt <= x) return true;
else return false;
}
那么,完整代码呈现一下:
CPP#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int N = 2e3 + 5;
int n, m, k, x, a[N][N], l, r, mid, ans, num[N * N], cnt = 0;
bool Check(int pos) {
int t = num[pos], lt = 0, gt = 0;
for (int i = 1; i <= n; i++) {
int p = upper_bound(a[i] + 1, a[i] + 1 + m, t) - a[i];
if (k >= p) lt += k - p + 1;
else gt += p - k - 1;
}
if (lt <= gt && lt <= x) return true;
else return false;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) cin >> a[i][j], num[++cnt] = a[i][j];
sort(a[i] + 1, a[i] + 1 + m);
}
sort(num + 1, num + 1 + cnt);
cnt = unique(num + 1, num + 1 + cnt) - num;
cin >> k >> x;
k = m - k + 1;
// max a[k]
l = 1, r = cnt;
while (l <= r) {
mid = (l + r) >> 1;
if (Check(mid)) {
ans = mid;
r = mid - 1;
} else l = mid + 1;
}
cout << num[ans] << '\n';
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...