题解:P15819 [JOI 2015 Final] 舞会 / Ball
联考 T2,又没有写出来,又急哭了。
考虑二分这谁想得到最后的答案 经典在哪将所有
那么我们便将这题转换成了这样一个问题:有一些固定或不固定的
这个感觉不太好做,或许可以考虑这样的一个东西,假设我有一个已经排列好的长度为
我对它进行一次操作,就变成了这样:
(其中
再来一次:
(其中
再来一次:
(其中
最后一次就是
你发现了什么?反正我什么也没有发现。
每一次进行的操作,都只跟队首的那三个数中最多的那个数(也就是中位数)有关,并且这个东西是无后效性的,这启示我们对这一个东西 dp。
想一个好计算答案的状态,定义
转移也是简单的,对于前面三个数
实现的话用个 deque 就好了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5;
int a[N], b[N], t[N], n, m;
bool check(int mid) {
deque<int> q;
for (int i = 1; i <= n; i++) {
if (t[i] >= mid) {
q.push_back(0);
} else if (t[i] == 0) {
q.push_back(1);
} else {
q.push_back(INT_MAX);
}
}
int res = 0;
for (int i = m + 1; i <= n; i++) {
if (a[i] >= mid) {
res++;
}
}
while (q.size() != 1) {
int x = q.front();
q.pop_front();
int y = q.front();
q.pop_front();
int z = q.front();
q.pop_front();
q.push_back(x + y + z - max({x, y, z}));
}
return q.front() <= res;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
int T = 1;
// cin >> T;
while (T--) {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> a[i] >> b[i];
t[b[i]] = a[i];
}
for (int i = m + 1; i <= n; i++) {
cin >> a[i];
}
int l = 1, r = 1e9;
// cout << check(6) << '\n';
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) {
l = mid + 1;
} else {
r = mid - 1;
}
}
cout << r;
}
return 0;
}