题解 P4025 【[PA2014]Bohater】

· · 题解

LG4025 Bohater

传送门:https://www.luogu.com.cn/problem/P4025

题意

一开始有 z 点血。有 n 只怪物,每只怪物需要先消耗 d_i 点血,然后会恢复 a_i 点血。中途不能死掉。求一种可行的打怪顺序。

一个需要思考的贪心。 ## 题解 首先一个很明显的贪心,先打打了可以回血的怪物,再打打了会掉血的怪物。 这个贪心的一个证明:假如一个回血怪物放在掉血怪物前面都没法打掉,那么放在掉血怪物后面更不可能打掉。 然后考虑回血怪物以及掉血怪物内部的安排贪心。 先考虑回血怪物。 1. 对于那些 $d_i<z$ 的回血怪物,直接打即可。 2. 对于不能的,按照 $d_i$ 从小到大排序。可以用调整法证明。 然后考虑掉血怪物。有两种理解方法。第一种还是用调整法来做。第二种我们可以发现,如果倒过来反向看,掉血怪物相当于回血怪物(从终局往回走,$a_i$ 作为掉血量,$d_i$ 作为回血量,每次血量都不能小于 $0$),于是我们按照倒叙视角的“掉血量”排序,即按照 $a_i$ 排序。 排完序模拟即可。 ```cpp #include<bits/stdc++.h> #define int long long #define rep(i,a,b) for(register int i=(a);i<=(b);i++) using namespace std; const int N=1e5+9; int n,sum,ans[N]; struct mons {int d,a,id;} a[N]; bool cmp(const mons &x, const mons &y) { if((x.a-x.d)*(y.a-y.d)<0) return x.a-x.d>0; else if(x.a-x.d<0) return x.a>y.a; else return x.d<y.d; } inline int read() { register int x=0, f=1; register char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-48,c=getchar();} return x*f; } signed main() { n=read(), sum=read(); rep(i,1,n) a[i].d=read(), a[i].a=read(), a[i].id=i; sort(a+1,a+n+1,cmp); rep(i,1,n) { sum-=a[i].d; if(sum<=0) return puts("NIE"), 0; ans[i]=a[i].id; sum+=a[i].a; } puts("TAK"); rep(i,1,n) printf("%lld ",ans[i]); return 0; } ```