【刷题】BZOJ 4977 [Lydsy1708月赛]跳伞求生
Description
小Q最近沉迷于《跳伞求生》游戏。他组建了一支由n名玩家(包括他自己)组成的战队,编号依次为1到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战队的指挥,请制定一套最优的降
落方案,使得最后获得的团队奖励总积分最大
Input
第一行包含两个正整数n,m(1<=n,m<=100000),分别表示战队的玩家数和地面上的房间数。
第二行包含n个正整数a_1,a_2,...,a_n(1<=a_i<=100000),分别表示每个玩家的子弹数。
接下来m行,每行两个正整数b_i,c_i(1<=b_i,c_i<=100000),分别表示每个敌人的子弹数和奖励积分。
Output
输出一行一个整数,即最后获得的团队奖励总积分的最大值。
Sample Input
3 3
4 4 4
2 3
1 3
5 3
Sample Output
11
Solution
这题有很简单的做法,也有很复杂的做法
这里写个简单的贪心
首先把房子按照 \(c_i-b_i\) 排序,然后依次枚举,每次看第 \(i\) 个房子能不能被打掉,如果能就用大于 \(b_i\) 的最小 \(a_j\) 去打。但是这里并不代表钦定这个 \(a_j\) 去打 \(b_i\) ,因为不一定最优,这里只是把能打的房子先标记下来
知道了哪些房子可以打掉,之后将 \(a\) 数组从大到小排序,用最大的 \(a_j\) 去打最大的 \(c_i-b_i\) ,使得获得收益最大。
这里有两个细节
- 会出现到一个 \(c_i-b_i\) ,它所对应的 \(a_j\) 其实打不了这个房子。但是这对答案是没有影响的,因为打掉这个房子的人在前面一定算过了。此时只需要把两者交换一下过程就可行了,但是不交换贡献是不会变的,所以直接算就好了
- 题目要求的是最大权值,但不需要保证前提是打尽量多的房子,所以当我们枚举到某一次的贡献小于 \(0\) 的时候,就不需要再加了
#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100000+10;
int n,m,a[MAXN],in[MAXN],val[MAXN],cnt;
ll ans;
struct node{
int b,c;
inline bool operator < (const node &A) const {
return c-b>A.c-A.b;
};
};
node room[MAXN];
std::multiset<int> S;
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
int main()
{
read(n);read(m);
for(register int i=1;i<=n;++i)read(a[i]),S.insert(a[i]);
for(register int i=1;i<=m;++i)read(room[i].b),read(room[i].c);
std::sort(room+1,room+m+1);
for(register int i=1;i<=m;++i)
{
std::set<int>::iterator it=S.upper_bound(room[i].b);
if(it!=S.end())val[++cnt]=room[i].c-room[i].b,S.erase(it);
}
std::sort(a+1,a+n+1,std::greater<int>());
for(register int i=1;i<=cnt;++i)
if((ll)a[i]+val[i]>0)ans+=(ll)a[i]+val[i];
write(ans,'\n');
return 0;
}