想复杂了……
这种分到两边的问题,考虑建立费用流模型,建立两个点 \(A,B\) 表示分到 \(A\) 的数或者分到 \(B\) 的数:
- \(S\to A\),流量 \(p\),费用 \(0\)。
- \(S\to B\),流量 \(s\),费用 \(0\)。
- \(A\to i\in[1,n]\),流量 \(1\),费用 \(a_i\)。
- \(B\to i\in [1,n]\),流量 \(1\),费用 \(b_i\)。
- \(i\in[1,n]\to T\),流量 \(1\),费用 \(0\)。
建图方式很好理解,跑费用流(最大费用)后如果 \(A\to i\) 的边流量为 \(0\) 就代表选到了 \(A\),\(B\) 同理。
然后考虑每次增广的过程,有 \(2\) 种情况:
一种是 \(S\to C(A\text{\ 或者\ }B)\to i\to T\),由于 \(C\to i\) 和 \(i\to T\) 本来流量为 \(1\),可以增广说明原本就没选。对应取一个没被选的 \(i\) 加进 \(C\) 集合的方案,那肯定是选 \(\max\limits_{i\notin A\cup B}\{a_i\}\)。
另一种是 \(S\to A\to i\to B\to j\to T\)(或者 \(S\to B\to i\to A\to j\to T\),不难发现绕多几圈肯定不优),不难发现 \(i\to B\) 如果能流,代表原本 \(i\) 在 \(B\) 集合里,现在被移动到了 \(A\) 集合。原本 \(j\) 也没有被选过。所以对应从 \(B\) 里面取一个 \(i\) 扔到 \(A\),再从没选过的数里选一个扔进 \(B\) 的方案。由于对答案的贡献为 \(a_i-b_i+b_j\),所以肯定是取 \(\max\limits_{i\in B}\{a_i-b_i\}+\max\limits_{j\notin A\cup B}\{b_j\}\),\(A\) 扔到 \(B\) 的情况类似。
所以只需要维护 \(4\) 种情况,开 \(4\) 个堆,分别维护还没被选的数中最大 \(a_i\)、还没被选数中最大 \(b_i\)、\(B\) 集合中最大 \(a_i-b_i\) 以及 \(A\) 集合中最大 \(b_i-a_i\) 即可。
复杂度 \(O(n\log n)\)。代码很好写。
#include <bits/stdc++.h>
using namespace std;
namespace vbzIO {
char ibuf[(1 << 20) + 1], *iS, *iT;
#if ONLINE_JUDGE
#define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
#else
#define gh() getchar()
#endif
#define rd read
#define wr write
#define pc putchar
#define pi pair<int, int>
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define ins insert
#define era erase
inline int read () {
char ch = gh();
int x = 0;
bool t = 0;
while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
return t ? ~(x - 1) : x;
}
inline void write(int x) {
if (x < 0) {
x = ~(x - 1);
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
}
using vbzIO::read;
using vbzIO::write;
const int N = 3e3 + 300;
int n, ans, p1, p2, a[N], b[N], in[N];
priority_queue<pi> q0, q1, q2, q3;
int main() {
n = rd(), p1 = rd(), p2 = rd();
for (int i = 1; i <= n; i++) a[i] = rd(), q0.push(mp(a[i], i));
for (int i = 1; i <= n; i++) b[i] = rd(), q1.push(mp(b[i], i));
while (p1 || p2) {
int d = -1e9, op = -1;
while (!q0.empty() && in[q0.top().se]) q0.pop();
while (!q1.empty() && in[q1.top().se]) q1.pop();
while (!q2.empty() && in[q2.top().se] != 2) q2.pop();
while (!q3.empty() && in[q3.top().se] != 1) q3.pop();
if (p1 && !q0.empty()) if (q0.top().fi > d) d = q0.top().fi, op = 0;
if (p2 && !q1.empty()) if (q1.top().fi > d) d = q1.top().fi, op = 1;
if (p1 && !q2.empty() && !q1.empty()) if (q2.top().fi + q1.top().fi > d) d = q2.top().fi + q1.top().fi, op = 2;
if (p2 && !q3.empty() && !q0.empty()) if (q3.top().fi + q0.top().fi > d) d = q3.top().fi + q0.top().fi, op = 3;
if (!op) {
auto tp = q0.top(); q0.pop();
p1--, ans += d, in[tp.se] = 1;
q3.push(mp(b[tp.se] - a[tp.se], tp.se));
} else if (op == 1) {
auto tp = q1.top(); q1.pop();
p2--, ans += d, in[tp.se] = 2;
q2.push(mp(a[tp.se] - b[tp.se], tp.se));
} else if (op == 2) {
auto t1 = q2.top(), t2 = q1.top(); q2.pop(), q1.pop();
p1--, ans += d, in[t2.se] = 2, in[t1.se] = 1;
q2.push(mp(a[t2.se] - b[t2.se], t2.se));
q3.push(mp(b[t1.se] - a[t1.se], t1.se));
} else if (op == 3) {
auto t1 = q3.top(), t2 = q0.top(); q3.pop(), q0.pop();
p2--, ans += d, in[t2.se] = 1, in[t1.se] = 2;
q2.push(mp(a[t1.se] - b[t1.se], t1.se));
q3.push(mp(b[t2.se] - a[t2.se], t2.se));
} else break;
}
wr(ans), puts("");
for (int i = 1; i <= n; i++)
if (in[i] == 1) wr(i), pc(' ');
puts("");
for (int i = 1; i <= n; i++)
if (in[i] == 2) wr(i), pc(' ');
return 0;
}
标签:q1,t2,top,Programming,t1,fi,Olympiad,CF730I,se
From: https://www.cnblogs.com/Ender32k/p/17569305.html