CF730I Olympiad in Programming and Sports
想复杂了……
这种分到两边的问题,考虑建立费用流模型,建立两个点 表示分到 的数或者分到 的数:
- ,流量 ,费用 。
- ,流量 ,费用 。
- ,流量 ,费用 。
- ,流量 ,费用 。
- ,流量 ,费用 。
建图方式很好理解,跑费用流(最大费用)后如果 的边流量为 就代表选到了 , 同理。
然后考虑每次增广的过程,有 种情况:
一种是 ,由于 和 本来流量为 ,可以增广说明原本就没选。对应取一个没被选的 加进 集合的方案,那肯定是选 。
另一种是 (或者 ,不难发现绕多几圈肯定不优),不难发现 如果能流,代表原本 在 集合里,现在被移动到了 集合。原本 也没有被选过。所以对应从 里面取一个 扔到 ,再从没选过的数里选一个扔进 的方案。由于对答案的贡献为 ,所以肯定是取 , 扔到 的情况类似。
所以只需要维护 种情况,开 个堆,分别维护还没被选的数中最大 、还没被选数中最大 、 集合中最大 以及 集合中最大 即可。
复杂度 。代码很好写。
#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;
}
标签:
模拟费用流
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现