bzoj3709:[PA2014]Bohater
题目描述
在一款电脑游戏中,你需要打败n只怪物(从1到n编号)。为了打败第i只怪物,你需要消耗d[i]点生命值,但怪物死后会掉落血药,使你恢复a[i]点生命值。任何时候你的生命值都不能降到0(或0以下)。请问是否存在一种打怪顺序,使得你可以打完这n只怪物而不死掉
输入
第一行两个整数n,z(1<=n,z<=100000),分别表示怪物的数量和你的初始生命值。
接下来n行,每行两个整数d[i],a[i](0<=d[i],a[i]<=100000)
输出
第一行为TAK(是)或NIE(否),表示是否存在这样的顺序。
如果第一行为TAK,则第二行为空格隔开的1~n的排列,表示合法的顺序。如果答案有很多,你可以输出其中任意一个。
样例输入
3 5
3 1
4 8
8 3
3 1
4 8
8 3
样例输出
TAK
2 3 1
2 3 1
题解
分成三种怪物,打完加血,不加不减,打完减血。
贪心可知,先打加血的,再打不加不减,最后打减血怪。
加血怪先打减血少的,减血怪先打加血多的。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define maxn 100005 5 using namespace std; 6 struct fuck{int a,d,x;}add[maxn],take[maxn],com[maxn]; 7 bool cmp1(fuck p,fuck q){return p.d<q.d;} 8 bool cmp2(fuck p,fuck q){return p.a>q.a;} 9 int n,cnt,tcnt,acnt; 10 long long z; 11 int main() 12 { 13 int d,a; 14 scanf("%d%lld",&n,&z); 15 for(int i=1 ; i<=n ; ++i ) 16 { 17 scanf("%d%d",&d,&a); 18 if(a-d>0){add[++acnt].d=d;add[acnt].a=a;add[acnt].x=i;} 19 else if(a-d<0){take[++tcnt].d=d;take[tcnt].a=a;take[tcnt].x=i;} 20 else{com[++cnt].d=d;com[cnt].a=a;com[cnt].x=i;} 21 } 22 sort(add+1,add+1+acnt,cmp1); 23 sort(take+1,take+1+tcnt,cmp2); 24 for(int i=1 ; i<=acnt ; ++i ) 25 if(z-add[i].d<=0){printf("NIE");return 0;} 26 else z=z-add[i].d+add[i].a; 27 for(int i=1 ; i<=cnt ; ++i )if(z-com[i].d<=0){printf("NIE");return 0;} 28 for(int i=1 ; i<=tcnt ; ++i ) 29 if(z-take[i].d<=0){printf("NIE");return 0;} 30 else z=z-take[i].d+take[i].a; 31 printf("TAK\n"); 32 for(int i=1 ; i<=acnt ; ++i)printf("%d ",add[i].x); 33 for(int i=1 ; i<=cnt ; ++i)printf("%d ",com[i].x); 34 for(int i=1 ; i<=tcnt ; ++i)printf("%d ",take[i].x); 35 return 0; 36 }