BZOJ4977 跳伞求生题解
题意:有
个队友和 个敌人,每个队友 有 颗子弹。敌人 有 颗子弹。
队友击杀敌人,必须,然后会获得 的收益。( : 每个敌人都有一个参数)
每个队友只能打一个敌人,可以不打。求最大收益。
【费用流模型】
上面那一排点表示队友,下面一排点表示敌人。若队友
求最大费用任意流。
【模拟费用流】
任意流的题目一般都是用增量算法。
直接来不好弄,因为每个队友能杀什么敌人是随机的,我们还要遍历一遍。
可以观察一个性质:如果把队友和敌人都按子弹数量从小到大排序,每个队友打的都是一个前缀。
也就是这样:
考虑新增加点
新的增广路有哪几种?
第一条增广路的收益是
第二条增广路的收益是
那这两种有什么区别呢?其实没有区别。较复杂的增广路只是让每个队友匹配的敌人变了。但是其实哪个队友匹配哪个敌人没有任何影响。
所以可以统合为:
然后考虑环。
一种:
收益是
两种:
收益是
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
int n, m;
ll a[N];
int pos[N]; //a[i]能打1~pos[i]
struct Enemy {
ll b, w, c;
} e[N];
bool cmp(Enemy a, Enemy b) {
return a.b < b.b;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= m; i++) {
cin >> e[i].b >> e[i].w;
e[i].c = -e[i].b + e[i].w;
}
sort(a + 1, a + n + 1);
sort(e + 1, e + m + 1, cmp);
for (int i = 1, j = 0; i <= n; i++) {
while (j + 1 <= m && e[j + 1].b < a[i])
j++;
pos[i] = j;
}
ll ans = 0;
priority_queue<ll> q;
priority_queue<ll, vector<ll>, greater<ll> > q2;
for (int i = 1; i <= n; i++) {
for (int j = pos[i - 1] + 1; j <= pos[i]; j++)
q.push(e[j].c);
ll tmp1 = -1, tmp2 = -1;
if (!q.empty())
tmp1 = a[i] + q.top();
if (!q2.empty())
tmp2 = a[i] - q2.top();
if (tmp1 < 0 && tmp2 < 0)
continue;
if (tmp1 > tmp2) {
ans += tmp1;
q.pop();
q2.push(a[i]);
}
else {
ans += tmp2;
q2.pop();
q2.push(a[i]);
}
}
cout << ans << endl;
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战