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
3 1
4 8
8 3
Sample Output
TAK
2 3 1
2 3 1
最优的情况我们肯定先把所有打了可以回血的怪全刷了。
所以按怪的消耗排序,如果它可以加血,就打它。
然后加血的处理完了我们该考虑如何应对打了还减血的怪。
不充钱不可能的
因为怎么打都减血,并且最后的血量是一定的。
所以可以倒过来想,发现正好和上面的问题相反...
你最初有一个确定的血量,把加血想象成扣血,扣血想象成加血, 那么就和第一问一样了。
所以仿照第一问按照减血从小到大排序,反过来就变成了按加血从大打到小。
#include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <algorithm> #include <queue> using namespace std; inline int read(){ int res=0;char ch=getchar(); while(!isdigit(ch)) ch=getchar(); while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();} return res; } #define int long long int n, hp; struct date{ int x, y, c, id; }p[100005]; inline bool cmp(date a, date b) { return a.x < b.x; } inline bool cmp2(date a, date b) { return a.y > b.y; } bool use[100005]; int road[100005], top; signed main() { n = read(), hp = read(); for (int i = 1 ; i <= n ; i ++) { p[i].x = read(), p[i].y = read(); p[i].c = p[i].y - p[i].x;p[i].id = i; } sort(p + 1, p + 1 + n, cmp); for (int i = 1 ; i <= n ; i ++) { if (p[i].x >= hp) return puts("NIE"), 0; else if (p[i].c >= 0) hp += p[i].c, use[p[i].id] = 1, road[++top] = p[i].id; } if (top == n) { puts("TAK"); for (int i = 1 ; i <= n ; i ++) printf("%lld ", road[i]); return 0; } sort(p + 1, p + 1 + n, cmp2); for (int i = 1 ; i <= n ; i ++) { if (use[p[i].id]) continue; if (hp - p[i].x <= 0) return puts("NIE"), 0; else hp += p[i].c, road[++top] = p[i].id; } puts("TAK"); for (int i = 1 ; i <= n ; i ++) printf("%lld ", road[i]); return 0; return 0; }