【题解】P4025 [PA2014]Bohater
解
很清奇的贪心策略题
主要是将所有的怪分成两种——$ d<a $的刷分回血怪和 $ d > a$ 的让人残血的BOSS
我们分开处理,先把所有的的刷分怪打完,这样血达到最厚,再去打BOSS
刷分怪先打血少的,也就是按d升序
BOSS先打血药大的,也就是按a降序,这里很神奇
详见代码
code
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define ci cosnt int &
using namespace std;
const int maxn = 100010;
int n, d, a, tot, top;
ll blood;
struct Blood{
int d, a, del, id;
}add[maxn], lss[maxn];
bool cmp1(Blood a, Blood b){
//不要想着多加血,要防止打怪时死 ,下面这样写就不对咯
// return a.del > b.del;
//以下为正解贪心策略-----------------------------------------
//对于刷分怪,要防止打怪的时候死掉
//在不断的刷分当中,会一直加血,越往后血越多,应对刷分怪时能掉的血也越多
//全部刷完分后再去打会残血的BOSS,所以刷分怪的顺序只对刷分怪有影响,对BOSS无影响
return a.d < b.d;
}
bool cmp2(Blood a, Blood b){
//又是错误的写法哦
// return a.d > b.d;//当然先打掉血多的
//残血怪,持续掉血,
//以下为正解------------------------------------------
//倒着考虑,我们有一个最后的血量lastblood,打完刷分怪后得到的血量是maxblood,
//全程回放,回放一个BOSS相当于吐出血药,收回残掉的血,也就是lastblood-=a,lastblood+=d,
//这是一个加血的过程,全部回放完时,lastblood就回到了maxblood。
//我们要保证回放的过程中的最优,贪心策略同cmp1,即a.a < b.a,
//那么正过来看,排序策略就是a.a > b.a 。
return a.a > b.a;
}
int main(){
scanf("%d%d",&n,&blood);
for(int i=1;i<=n;i++){
scanf("%d%d",&d,&a);
if(d > a){
lss[++tot].a = a;
lss[tot].d = d;
lss[tot].del = a - d;
lss[tot].id = i;
}
else{
add[++top].a = a;
add[top].d = d;
add[top].del = a - d;
add[top].id = i;
}
}
sort(add + 1, add + 1 + top, cmp1);
sort(lss + 1, lss + 1 + tot, cmp2);
if(blood <= 0){
printf("NIE\n");
return 0;
}
for(int i = 1; i <= top; i++){
if(blood - add[i].d <= 0){
printf("NIE\n");
return 0;
}
blood += add[i].del;
}
for(int i = 1; i <= tot; i++){
if(blood - lss[i].d <= 0){
printf("NIE\n");
return 0;
}
blood += lss[i].del;
}
printf("TAK\n");
for(int i = 1; i <= top; i++){
printf("%d ",add[i].id);
}
for(int i = 1; i <= tot; i++){
printf("%d ",lss[i].id);
}
printf("\n");
return 0;
}