其他分享
首页 > 其他分享> > 题解 P4025 [PA2014]Bohater

题解 P4025 [PA2014]Bohater

作者:互联网

题目中没有说怪物掉落的血药 \(a_i\) 和消耗的生命值 \(d_i\) 的大小关系,所以我们可以把怪物分为两类:补血怪(\(d_i\le a_i\))与掉血怪(\(d_i> a_i\))。

容易发现的是,一定是先打完补血怪再打掉血怪。因为打掉血怪没有益处,反而减少生命值。所以我们把它分为两部分,第一部分是打补血怪,第二部分是打掉血怪。

第一部分,在打每个补血怪时的要求是 \(z>d_i\)。由于 \(z\) 会逐渐变大,所以应当先打 \(d_i\) 小的怪物。

第二部分,在打每个掉血怪时的要求是 \(z>d_i\)。但是 \(z\) 会逐渐变小,我们不能先打 \(d_i\) 小/大的怪物。怎么办?我们考虑倒序,计算打完所有怪物后的剩余生命值,从最后开始考虑。每一个怪物相当于让 \(z\) 先减去 \(a_i\) 再加上 \(d_i\)。条件变成了 \(z>a_i\)。由于是倒序,\(z\) 会逐渐增大,所以倒序按 \(a_i\) 从小到大打就行了。调整回正序就是按照 \(a_i\) 从大到小。

感觉有异曲同工之妙的题目

以下是部分代码(几乎全部)。

#define ll long long
const int N=100005;
ll n,z;
struct mon
{
	ll d,a;
	int id;
}a[N],b[N],c;
int cnta,cntb;
bool cmp1(mon x,mon y)
{
	return x.a<y.a;
}
bool cmp2(mon x,mon y)
{
	return x.d<y.d;
}
int main()
{
	n=read(),z=read();
	ll p=z;
	for (int i=1;i<=n;i++) 
	{
		c.d=read(),c.a=read(),c.id=i;
		if (c.d>c.a) b[++cntb]=c;
		else a[++cnta]=c;
		z-=c.d,z+=c.a;
	}
	sort(a+1,a+cnta+1,cmp2);
	sort(b+1,b+cntb+1,cmp1);
	for (int i=1;i<=cntb;i++) 
	{
		if (z>b[i].a) z+=b[i].d-b[i].a;
		else 
		{
			puts("NIE");
			return 0;
		}
	}
	z=p;
	for (int i=1;i<=cnta;i++) 
	{
		if (z>a[i].d) z+=-a[i].d+a[i].a;
		else 
		{
			puts("NIE");
			return 0;
		}
	}
	puts("TAK");
	for (int i=1;i<=cnta;i++) cout << a[i].id << " ";
	for (int i=cntb;i>=1;i--) cout << b[i].id << " ";
	return 0;
}

标签:P4025,int,题解,PA2014,补血,怪物,掉血,倒序,ll
来源: https://www.cnblogs.com/irty/p/14954139.html