Assassin’s Creed贪心)

F - Assassin’s Creed
Time Limit:2000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Submit

Status
Description
Ezio Auditore is a great master as an assassin. Now he has prowled in the enemies’ base successfully. He finds that the only weapon he can use is his cuff sword and the sword has durability m. There are n enemies he wants to kill and killing each enemy needs Ai durability. Every time Ezio kills an enemy he can use the enemy’s sword to kill any other Bi enemies without wasting his cuff sword’s durability. Then the enemy’s sword will break. As a master, Ezio always want to do things perfectly. He decides to kill as many enemies as he can using the minimum durability cost.
Input
The first line contains an integer T, the number of test cases.
For each test case:
The first line contains two integers, above mentioned n and m (1<=n<=10^5, 1<=m<=10^9).
Next n lines, each line contains two integers Ai, Bi. (0<=Ai<=10^9, 0<=Bi<=10).
Output
For each case, output “Case X: ” (X is the case number starting from 1) followed by the number of the enemies Ezio can kill and the minimum durability cost.
Sample Input
2
3 5
4 1
5 1
7 7
2 1
2 2
4 0
Sample Output
Case 1: 3 4
Case 2: 0 0

题意:
有n个敌人,你现在的武器的耐久度为m,杀每个敌人要消耗Ai点耐久度,同时得到可以再杀死Bi个人的权利。问最多可以杀死多少人,在杀人最多的情况下最少要消耗多少耐久度?

分析:
首先会想到对人进行分类,一类是B为0的,一类是B不为0的。
因为杀死一个B不为0的,一定能杀死所有B不为0的,而且还能再额外杀死B为0的。
于是就先分出第一种情况:不杀B不为0的人
这样就是对B为0的人进行贪心,优先杀消耗耐久度最小的即可。
考虑第二种情况:杀死至少一个B不为0的人。
那么首先前提自然是保证能杀死B不为0的人里面消耗耐久度最少的。
然后就可以杀死所有B不为0的人。而且还能再额外杀死B为0的。
最后就是用剩余耐久度去杀死剩下的B为0的人。
但是这样会出现一种情况。就是虽然B不为0的人,可以自动杀死,但是如果我手动杀死一个B不为0的人,可以多出一个名额杀死一个B为0的人,也许这样我会消耗更低的耐久度去手动杀死一个人。
于是就发现,肯定可以杀死所有B不为0的人,但是可以优先手动杀死耐久度小的。
得出结论:杀死第一个耐久度最小的B不为0的人后,我便按照耐久度从小到大手动杀人。
此处还要注意的是,我依次杀人后,如果剩下的人都能被自动杀死,我便不需要再手动杀死人了。

最后就是两种情况取最值了。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <utility>
#include <queue>
#include <vector>
#define LL long long

using namespace std;

typedef pair<int, int> pii;
const int maxN = 1e5+5;
int n, m;
struct node
{
    int need;
    int kill;
}p[2][maxN];
int top[2];
int can;

bool cmpNeedLest(node x, node y)
{
    return x.need < y.need;
}

void input()
{
    scanf("%d%d", &n, &m);
    can = 0;
    top[0] = top[1] = 0;
    int need, kill;
    for (int i = 0; i < n; ++i)
    {
        scanf("%d%d", &need, &kill);
        if (kill == 0)
        {
            p[0][top[0]].need = need;
            p[0][top[0]].kill = 0;
            top[0]++;
        }
        else
        {
            p[1][top[1]].need = need;
            p[1][top[1]].kill = kill;
            top[1]++;
            can += kill;
        }
    }
    sort(p[0], p[0]+top[0], cmpNeedLest);
    sort(p[1], p[1]+top[1], cmpNeedLest);
}

pii workOne()
{
    //p->p+top;
    int num = 0, rest = m;
    for (int i = 0; i < top[0]; ++i)
    {
        if (rest >= p[0][i].need)
        {
            num++;
            rest -= p[0][i].need;
        }
        else
            break;
    }
    return pii(num, m-rest);
}

pii workTwo()
{
    int rest = m, num = 0;
    int from[2];
    from[0] = from[1] = 0;
    if (top[1] == 0 || rest < p[1][0].need)
        return pii(0, 0);
    rest -= p[1][0].need;
    from[1]++;
    bool flag;
    for (;;)
    {
        if (n-(from[0]+from[1]) <= can)
            break;
        flag = false;
        if (from[1] < top[1] && p[0][from[0]].need > p[1][from[1]].need)
        {
            if (rest >= p[1][from[1]].need)
            {
                flag = true;
                rest -= p[1][from[1]].need;
                from[1]++;
                num++;
            }
        }
        else if (from[0] < top[0])
        {
            if (rest >= p[0][from[0]].need)
            {
                flag = true;
                rest -= p[0][from[0]].need;
                from[0]++;
                num++;
            }
        }
        if (!flag)
            break;
    }
    return pii(min(from[0]+from[1]+can, n), m-rest);
}

void work()
{
    pii one, two;
    one = workOne();
    two = workTwo();
    if (one.first > two.first)
        printf("%d %d\n", one.first, one.second);
    else if (one.first == two.first)
        printf("%d %d\n", one.first, min(one.second, two.second));
    else
        printf("%d %d\n", two.first, two.second);
}

int main()
{
    //freopen("test.in", "r", stdin);
    int T;
    scanf("%d", &T);
    for (int times = 1; times <= T; ++times)
    {
        input();
        printf("Case %d: ", times);
        work();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值