HDU 4864 贪心

题意

传送门 HDU 4864

题解

目标是最大化完成的任务数量,多解情况下最大化收益。

机器 ( x u , y u ) (x_u,y_u) (xu,yu) 能完成某个任务 ( x i , y i ) (x_i,y_i) (xi,yi),需要满足
{ x i ≤ x u y i ≤ y u \begin{cases} x_i\leq x_u\\ y_i\leq y_u\\ \end{cases} {xixuyiyu 那么最大化完成的任务数量,可以使用贪心策略。即将任务分别以 x i , y i x_i,y_i xi,yi 为第一、第二关键字排序,降序排序,顺序扫描任务,每次将任务分配给满足条件且第二关键字 y u y_u yu 最小的机器。

简单证明,考虑策略的作用范围拓展到后续其他任务产生的影响,对于后续任务 j j j,都满足第一关键字 x j ≤ x i x_j\leq x_i xjxi;即是说,当前任务可指派的机器,对于后续的任务在第一关键字上也满足条件;设当前任务可指派的任意 2 2 2 台机器 u , v u,v u,v 满足 y v ≤ y u y_v\leq y_u yvyu,那么后续任务只可能出现“ u , v u,v u,v 都能指派”,“ u , v u,v u,v 都不能指派”或者“ u u u 能指派, v v v 不能指派”三种情况之一,因此当前任务指派给第二关键字 y v y_v yv 较小的机器,对于整体问题的影响显然比选择第二关键字 y u y_u yu 较大的更好;考虑不完成当前任务的情况,由于每个任务对总数量的贡献至多是 1 1 1,故将它指派的机器分配给其他任务,对答案的贡献也不会更大。

对于每一个任务,完成获得的收益为 500 × x i + 2 × y i 500\times x_i+2\times y_i 500×xi+2×yi,可以观察到 2 × m a x y = 200 < 500 2\times maxy=200<500 2×maxy=200<500。那么以 x i x_i xi 为第一关键字, y i y_i yi 为第二关键字排序,顺序扫描可以保证优先处理可获得收益更多的任务,这正好匹配前述的贪心策略,那么在顺序处理任务,记录 y y y 的值域上可使用的机器数量,同时统计答案即可。

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100005
#define maxy 105
typedef long long ll;
struct node
{
    int x, y;
    bool operator<(const node &b) const
    {
        if (x != b.x)
            return x > b.x;
        return y > b.y;
    }
} mach[maxn], task[maxn];
int N, M, Y, cnt[maxy];

int main()
{
    while (~scanf("%d%d", &N, &M))
    {
        Y = 0;
        memset(cnt, 0, sizeof(cnt));
        for (int i = 0; i < N; ++i)
            scanf("%d%d", &mach[i].x, &mach[i].y), Y = max(Y, mach[i].y);
        for (int i = 0; i < M; ++i)
            scanf("%d%d", &task[i].x, &task[i].y);
        sort(mach, mach + N);
        sort(task, task + M);
        ll num = 0, mon = 0;
        for (int i = 0, j = 0; i < M; ++i)
        {
            while (j < N && mach[j].x >= task[i].x)
                ++cnt[mach[j++].y];
            for (int y = task[i].y; y <= Y; ++y)
            {
                if (cnt[y])
                {
                    --cnt[y], ++num, mon += task[i].x * 500 + task[i].y * 2;
                    break;
                }
            }
        }
        printf("%lld %lld\n", num, mon);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值