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;
}