bzoj 3709 [PA2014]Bohater 贪心

题面

题目传送门

解法

算法显然是贪心,dp显然不太可做

  • 假设怪的两个属性为 (x,y) ( x , y ) ,其中, x x 为先扣的血,y为后来回复的血量
  • 显然,肯定应该先选择 yx y ≥ x 的怪,对于这些怪的先后顺序显然是先打 x x 较小的,否则打x较大的直接就挂了
  • 然后再考虑剩下 x>y x > y 的怪,感觉没有 xy x ≤ y 那么简单了
  • 显然,如果最后能灭了所有怪,那么最后的血量是固定的
  • 不妨把时间倒流,就变成把回复的血量返还,然后再加上扣除的血量
  • 那么一定是先打 y y 比较小的,因为这样可以保证下一次扣血的时候能有尽量多的血量来消灭它
  • 所以,对于x>y的情况,按照 y y 的大小降序排序
  • 最后直接模拟一下就行了
  • 时间复杂度:O(nlogn)

代码

#include <bits/stdc++.h>
#define int long long
#define N 100010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
    x = 0; int f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Node {
    int x, y, num, id;
    bool operator < (const Node &a) const {
        return num < a.num;
    }
} a[N], b[N];
int ans[N];
main() {
    int n, m, l1 = 0, l2 = 0;
    read(n), read(m);
    for (int i = 1; i <= n; i++) {
        int x, y; read(x), read(y);
        if (x <= y) a[++l1] = (Node) {x, y, x, i};
            else b[++l2] = (Node) {x, y, -y, i};
    }
    sort(a + 1, a + l1 + 1), sort(b + 1, b + l2 + 1);
    int len = 0;
    for (int i = 1; i <= l1; i++)
        if (m <= a[i].x) {cout << "NIE\n"; return 0;}
            else m += a[i].y - a[i].x, ans[++len] = a[i].id;
    for (int i = 1; i <= l2; i++)
        if (m <= b[i].x) {cout << "NIE\n"; return 0;}
            else m += b[i].y - b[i].x, ans[++len] = b[i].id;
    cout << "TAK\n";
    for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
    cout << "\n";
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值