cf1607 H. Banquet Preparations 2(贪心)

https://codeforces.com/contest/1607/problem/H

题意:

每个盘子里有ai个白球和bi个黑球。现要从每个盘子里拿走mi个球,使不同的盘子数量最小。两个盘子相等是指白球和黑球的个数分别相等。题目保证每个盘子里的球数不少于m

思路:

对于任意两个盘子,只有当它们的 \(a_i+b_i-m_i\) 相等时才有可能让这两个盘子相等。

考虑一组 \(a_i+b_i-m_i\) 相等的盘子。每个盘子剩下的白球有一个最小值和最大值,且这个盘子剩下的白球数能取到中间的任一值。可以处理出每个盘子区间 \([l_i,r_i]\) ,问题转化为在数轴中取尽量少的点,使每个区间都至少包含一个点。区间按右端点排序然后贪心取右端点即可

#include <bits/stdc++.h>
using namespace std;

const signed N = 2e5+10;

struct Dish
{
    int id, a, b, m, l, r, res;
    void read(int i)
    {
        id = i; cin >> a >> b >> m;
        l = a - min(a, m), r = a - max(0, m - b);
        res = a + b - m;
    }
    bool operator< (const Dish &t)
    {
        if(res != t.res) return res < t.res;
        else return r < t.r;
    }
} dish[N];
pair<int, int> ans[N];

signed main()
{
    int T; cin >> T; while(T--)
    {
        int n; cin >> n;
        for(int i = 1; i <= n; i++) dish[i].read(i);

        sort(dish + 1, dish + 1 + n); dish[0].res = -1;

        int cnt = 0, nowr = 0;
        for(int i = 1; i <= n; i++)
        {
            if(dish[i].res != dish[i-1].res || dish[i].l > nowr)
                cnt++, nowr = dish[i].r;
            ans[dish[i].id].first = dish[i].a - nowr;
            ans[dish[i].id].second = dish[i].m - ans[dish[i].id].first;
        }

        cout << cnt << '\n';
        for(int i = 1; i <= n; i++)
            cout << ans[i].first << ' ' << ans[i].second << '\n';
    }

    return 0;
}

posted @ 2021-11-13 12:55  Bellala  阅读(82)  评论(0)    收藏  举报