题解:P8088 『JROI-5』Autumn
Hello_Coding · · 题解
Solution
思路:二分答案。
问是哪来的?看看题,最小化最大值嘛!
不会有不会二分答案模板的吧?先上一个:
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';
但是,这里我们要的是数组中的值,而非
// 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,我们现在要的就是 Check 函数了!
将每一个数列(记为
由于从大到小排序后期用 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;
}
那么,完整代码呈现一下:
#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;
}