题解 P4025 【[PA2014]Bohater】

这道题我们先来定义两个名词:
因为打一个怪既会掉血也会回血.
回血怪:掉的血比回的血少,打这个怪可以使我们回血,也就是\(d_i<a_i\)
掉血怪:掉的血比回的血多,打这个怪可以使我们掉血,也就是\(d_i>a_i\)

  • 思考:

Q:我们是先打回血的还是先打掉血的呢?

若我们先打掉血的,有可能血就掉没了,人没了.
若是先打回血的,我们可以以更多的血去打掉血的怪,活着的几率会大,所以,我们先去打回血的。

  • 思考:

Q:单对回血怪和掉血怪,我们怎么打呢?
回血怪:
对于这种怪,我们可分为两类。
一类是\(d_i \leq z\),也就是说我们一开始的时候就可以击杀,那他应该按什么顺序?
啥顺序都不用,因为无论怎么打,我们的血都会保持在安全范围之内,而且还会回血,不用去考虑还没等回血就over了的情况。

另一类是就是\(d_i > z\)的情况了,那这时候我们应该怎么打呢?
显然这时候不能再乱搞了,因为若没有一定的顺序,虽然会回血,但在回血之前就over了,那还回毛线血啊,所以我们要给怪安排一个合适的出场顺序。我们将伤害按从小到大排列,先打伤害低的,这样起码在低伤害之后还能回血,提高活的机会。

掉血怪:这时候我们可以按照回血量从大到小排序。
这时候就有同学问了:为什么不能按照掉血量从高到低排呢?我先用多的血打血的怪,这不也可以吗?
A:对啊,为啥呢,我一开始也是这么认为的。但我们再回想,若是这个怪他血多还回血少,下一个怪一定是剩下的怪里面掉血最多的,打不过怎么办?over了呀
所以我们从回血量的角度出发,我们可以保持一个较高的血量,即使面对血量大的怪,我们也有充足的准备,我不怕不怕啦
于是,这道题就这么完了。
十年OI一场空,不开long long 见祖宗
调了一个小时,就是因为没开long long,记得开long long

/*
work by smyslenny
2021.02.05
P4025 [PA2014]Bohater
*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iomanip>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#define orz cout<<"LKP AK IOI\n"
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn=1e5+5;
ll n,z,js=0,js_=0,j_s=0;
struct  monster_{
	ll num,d,a;
}mon[maxn],return_f[maxn],return_s[maxn],drop_[maxn];
inline int read()
{
	register int x=0;register int y=1;
	register char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=getchar();}
	return y?x:-x;
}
bool cmp(monster_ a,monster_ b)
{
	return a.d<b.d;
}
bool cmp_(monster_ a,monster_ b)
{
	return a.a>b.a;
}
int main()
{
	//freopen("3709.in","r",stdin);
	//freopen("3709.out","w",stdout);
	n=read(),z=read();
	js=0,js_=0,j_s=0;
	for(int i=1;i<=n;i++)
	{
		mon[i].num=i;
		mon[i].d=read();
		mon[i].a=read();
		if(mon[i].d-mon[i].a<0)
		{
			if(mon[i].d>z)
			return_s[++js]=mon[i];
			else
			return_f[++j_s]=mon[i];
		}
		else
		drop_[++js_]=mon[i];
	}
	sort(return_f+1,return_f+1+j_s,cmp);
	sort(return_s+1,return_s+1+js,cmp);
	sort(drop_+1,drop_+1+js_,cmp_);
	for(int i=1;i<=j_s;i++)
	{
		if(z-return_f[i].d<=0)//其实没有必要 
		{
			printf("NIE\n");
			return 0;
		}
		z-=return_f[i].d;
		z+=return_f[i].a;
	}
	for(int i=1;i<=js;i++)
	{
		if(z-return_s[i].d<=0)
		{
			printf("NIE\n");
			return 0;
		}
		z-=return_s[i].d;
		z+=return_s[i].a;
	}
	for(int i=1;i<=js_;i++)
	{
		if(z-drop_[i].d<=0)
		{
			printf("NIE\n");
			return 0;
		}
		z-=drop_[i].d;
		z+=drop_[i].a;
	}
	printf("TAK\n");
	for(int i=1;i<=j_s;i++)
	printf("%lld ",return_f[i].num);
	for(int i=1;i<=js;i++)
	printf("%lld ",return_s[i].num);
	for(int i=1;i<=js_;i++)
	printf("%lld ",drop_[i].num);
	return 0;
}
原文地址:https://www.cnblogs.com/jcgf/p/14379584.html