bzoj 3709: [PA2014]Bohater

3709: [PA2014]Bohater

链接

http://www.lydsy.com/JudgeOnline/problem.php?id=3709

题面

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

Input

第一行两个整数n,z(1<=n,z<=100000),分别表示怪物的数量和你的初始生命值。
接下来n行,每行两个整数d[i],ai

Output

第一行为TAK(是)或NIE(否),表示是否存在这样的顺序。
如果第一行为TAK,则第二行为空格隔开的1~n的排列,表示合法的顺序。如果答案有很多,你可以输出其中任意一个。

Sample Input

3 5

3 1

4 8

8 3

Sample Output

TAK

2 3 1

题解

看到数据范围,其实就不像是个dp,应该就是贪心。
把怪物分成两种怪物,第一种是回复>伤害的,我们按照伤害从低到高去打就是最优的。
第二种是伤害>回复的。我们打完所有怪物的时候,血量一定是固定的,所以我们先把把回血多的先杀掉,再杀回血少的。

代码

#include<bits/stdc++.h>
using namespace std;

vector<pair<pair<int,int>,int> >p1,p2;
vector<int> ans;
bool cmp1(pair<pair<int,int>,int> A,pair<pair<int,int>,int> B){
    return A.first.first<B.first.first;
}
bool cmp2(pair<pair<int,int>,int> A,pair<pair<int,int>,int> B){
    return A.first.second<B.first.second;
}

int main(){
    int n;
    long long z;
    scanf("%d%lld",&n,&z);
    for(int i=1;i<=n;i++){
        pair<pair<int,int>,int> x;
        scanf("%d%d",&x.first.first,&x.first.second);
        x.second = i;
        if(x.first.first>=x.first.second){
            p1.push_back(x);
        }else{
            p2.push_back(x);
        }
    }
    sort(p1.begin(),p1.end(),cmp1);
    for(int i=0;i<p1.size();i++){
        if(z<=p1[i].first.first){
            cout<<"NIE"<<endl;
            return 0;
        }else{
            z-=p1[i].first.first;
            z+=p1[i].first.second;
            ans.push_back(p1[i].second);
        }
    }
    sort(p2.begin(),p2.end(),cmp2);
    for(int i=p2.size()-1;i>=0;i--){
        if(z<=p2[i].first.first){
            cout<<"NIE"<<endl;
            return 0;
        }else{
            z-=p2[i].first.first;
            z+=p2[i].first.second;
            ans.push_back(p2[i].second);
        }
    }
    cout<<"TAK"<<endl;
    for(int i=0;i<ans.size();i++){
        cout<<ans[i]<<" ";
    }
    cout<<endl;
}
posted @ 2017-09-07 16:24 qscqesze 阅读(...) 评论(...) 编辑 收藏