题解 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