BZOJ

题意:在一款电脑游戏中,你需要打败\(n(n<=100000)\)只怪物(从1到n编号).为了打败第i只怪物,你需要消耗\(a[i]\)点生命值,但怪物死后会掉落血药,使你恢复\(b[i]\)点生命值。任何时候你的生命值都不能降到0(或0以下).请问是否存在一种打怪顺序,使得你可以打完这n只怪物而不死掉.

分析:很明显的贪心策略,首先打能够回血的怪物,再打剩下的怪物.而能够回血的怪物中,按照消耗的生命值从小到大排序(保证先打能打的).剩下的怪物按照回血量从大到小排序(反正都是掉血,保证每次回血尽量多一点)

排序后模拟做就好了.然后记得开\(long\) \(long\).

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=100005;
struct ppx{int x,y,id;}c[N],d[N];
inline bool cmp1(ppx x,ppx y){return x.x<y.x;}
inline bool cmp2(ppx x,ppx y){return x.y>y.y;}
int main(){
    int n=read();ll m=read(),tot=0,sum=0;
    for(int i=1;i<=n;++i){
        int a=read(),b=read();
        if(a<=b){
            c[++tot].x=a;
            c[tot].y=b;
            c[tot].id=i;//便于输出方案
        }//能够回血的放一起
        else{
            d[++sum].x=a;
            d[sum].y=b;
            d[sum].id=i;
        }//剩下的放一起
    }
    sort(c+1,c+tot+1,cmp1);
    sort(d+1,d+sum+1,cmp2);//分别排序
    for(int i=1;i<=tot;++i){//模拟
        m-=c[i].x;
        if(m<=0){puts("NIE");return 0;}
        m+=c[i].y;
    }
    for(int i=1;i<=sum;++i){//模拟
        m-=d[i].x;
        if(m<=0){puts("NIE");return 0;}
        m+=d[i].y;
    }
    puts("TAK");
    for(int i=1;i<=tot;++i)printf("%d ",c[i].id);
    for(int i=1;i<=sum;++i)printf("%d ",d[i].id);
    return 0;
}
02-11 16:44