【刷题】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='')
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
	if(ch!='')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,'
');
	return 0;
}
原文地址:https://www.cnblogs.com/hongyj/p/9518125.html