D2T2 跳伞求生

传送门

Description:

小Q最近沉迷于《跳伞求生》游戏。他组建了一支由 $n$ 名玩家(包括他自己)组成的战队,编号依次为$1,2,\dots,n$ 。这个游 戏中,每局游戏开始时,所有玩家都会从飞机上跳伞,选择一个目的地降落,跳伞和降落的时间有早有晚。在某局 游戏降落前,他们在空中观察发现地面上一共有 $m$ 间房子,编号依次为 $1$ 到 $m$ 。其中每间房子恰好有一名敌人早于他 们到达。小Q战队的第 $i$ 名玩家拥有 $a_i$发子弹,地面上第i间房子里的敌人拥有 $b_i$ 发子弹,消灭他可以获得 $c_i$ 点积 分。每名玩家必须且只能选择一间房子降落,然后去消灭里面的敌人。若第i名玩家选择了第j间房子,如果 $a_i>b_ j$ ,那么他就可以消灭该敌人,获得 $a_i-b_j+c_j$ 的团队奖励积分,否则他会被敌人消灭。为了防止团灭,小Q不允 许多名玩家选择同一间房子,因此如果某位玩家毫无利用价值,你可以选择让他退出游戏。因为房子之间的距离过长,你可以认为每名玩家在降落之后不能再去消灭其它房间里的敌人。作为小Q战队的指挥,请制定一套最优的降 落方案,使得最后获得的团队奖励总积分最大

Solution:

对于人的贡献为 $a_i$ ,房子的贡献为 $c_j-b_j$ 。 将 $c_j-b_j$ 从大到小排序。对于贡献大的房子,也要用 $a_i$ 大的取消除。用一个 $multiset$ 维护 $a$ ,如果有能消灭敌人的人,并更新答案。

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
#define in read()
#define ll long long
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
return x*f;
}
struct room{
int b,c,val;
}p[maxn];
int n,m,a[maxn];
multiset<int> s;
bool cmp1(int a,int b){
return a>b;
}
bool cmp2(room a,room b){
return a.val>b.val;
}
int main(){
n=in;m=in;
for(int i=1;i<=n;i++) a[i]=in,s.insert(a[i]);
for(int i=1;i<=m;i++){
p[i].b=in;p[i].c=in;
p[i].val=p[i].c-p[i].b;
}
sort(a+1,a+1+n,cmp1);
sort(p+1,p+1+m,cmp2);
ll ans=0,tot=0;
int cnt=0;
for(int i=1;i<=m;i++){
multiset<int>::iterator it=s.lower_bound(p[i].b+1);
if(it!=s.end()){
ans=max(ans,tot+=a[++cnt]+p[i].val);
s.erase(it);
}
}
printf("%lld\n",ans);
return 0;
}

诶难道不是线段树专题吗?因为这道题还可以用线段树模拟费用流来做