BZOJ3709: [PA2014]Bohater

BZOJ3709: [PA2014]Bohater

Description

在一款电脑游戏中,你需要打败n只怪物(从1到n编号)。

为了打败第i只怪物,你需要消耗d[i]点生命值,但怪物死后会掉落血药,使你恢复a[i]点生命值。

任何时候你的生命值都不能降到0(或0以下)。

请问是否存在一种打怪顺序,使得你可以打完这n只怪物而不死掉

Input

第一行两个整数n,z(1<=n,z<=100000),分别表示怪物的数量和你的初始生命值。
接下来n行,每行两个整数d[i],a[i](0<=d[i],a[i]<=100000)

Output

第一行为TAK(是)或NIE(否),表示是否存在这样的顺序。
如果第一行为TAK,则第二行为空格隔开的1~n的排列,表示合法的顺序。如果答案有很多,你可以输出其中任意一个。

Sample Input

3 5
3 1
4 8
8 3

Sample Output

TAK
2 3 1

题解Here!

这就是个贪心。。。

首先,先把杀掉能回血的先杀了,这是肯定的。

显然杀的顺序按照消耗升序。

杀完以后,不管用什么顺序杀掉剩下的怪,最后体力的剩余值是确定的。

倒序来看,相当于将血药吐出来然后返还杀怪的消耗,那么显然也是按照损失体力(即血药回血量)升序,正回来即是降序。。。

即分为两部分,杀完能回血的按照消耗升序,剩余按血药回血量降序,然后模拟一遍判断是否合法即可。

注:记得血量要开$long\ long$,活坑。。。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 100010
using namespace std;
int n;
long long m;
int top1=0,top2=0;
struct node{
	long long x,y;
	int id;
}a[MAXN],b[MAXN];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline bool cmp1(const node &p,const node &q){
	return p.x<q.x;
}
inline bool cmp2(const node &p,const node &q){
	return p.y>q.y;
}
void work(){
	for(int i=1;i<=top1;i++){
		if(m<=a[i].x){printf("NIE\n");return;}
		else m-=a[i].x-a[i].y;
	}
	for(int i=1;i<=top2;i++){
		if(m<=b[i].x){printf("NIE\n");return;}
		else m-=b[i].x-b[i].y;
	}
	printf("TAK\n");
	for(int i=1;i<=top1;i++)printf("%d ",a[i].id);
	for(int i=1;i<=top2;i++)printf("%d ",b[i].id);
	printf("\n");
}
void init(){
	n=read();m=read();
	for(int i=1;i<=n;i++){
		int x=read(),y=read();
		if(x<=y){
			top1++;
			a[top1].x=x;a[top1].y=y;
			a[top1].id=i;
		}
		else{
			top2++;
			b[top2].x=x;b[top2].y=y;
			b[top2].id=i;
		}
	}
	sort(a+1,a+top1+1,cmp1);
	sort(b+1,b+top2+1,cmp2);
}
int main(){
	init();
	work();
    return 0;
}
 

猜你喜欢

转载自www.cnblogs.com/Yangrui-Blog/p/9507374.html