1. 程式人生 > 其它 >cf1607 G. Banquet Preparations 1(貪心)

cf1607 G. Banquet Preparations 1(貪心)

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

題意:

給定陣列a[],b[]和整數m。每個盤子裡有ai個白球和bi個黑球。現要從每個盤子裡拿走m個球,使得剩下的所有白球的和與所有黑球的和的差的絕對值最小。題目保證每個盤子裡的球數不少於m

思路:

假設從每個盤子裡拿 \(x_i\) 個白球和 \(m-x_i\)個白球,那麼最後這個差的絕對值就是

\[\left| \sum_{i=1}^n (a_i-x_i) - \sum_{i=1}^n (b_i-(m-x_i)) \right| = \left| \sum_{i=1}^n (a_i-b_i+m-2x_i) \right| \\ = \left| nm+\sum_{i=1}^n (a_i-b_i) - 2\sum_{i=1}^n x_i \right| =|s - 2sumx| \]

每個 \(x_i\)

有最小值 \(mmin_i\) 和最大值 \(mmax_i\),所以 \(2sumx\) 也有最小值 \(2smin\) 和最大值 \(2smax\) 。而且 \(sumx\) 可以取到 \([smin, smax]\) 中的一切值!

如果 \(s >= 2smax\),答案就是 \(s-2smax\) ,每個盤子都要拿走 \(mmax_i\) 個白球;

如果 \(s <= 2smin\),答案就是 \(2smin-s\) ,每個盤子都要拿走 \(mmin_i\) 個白球;

如果 \(s\) 介於兩者之間,那就先都拿 \(mmin_i\) 保底,然後貪心拿球逼近 \(s\) 。答案為0或1,取決於 \(s\)

的奇偶性

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

const signed N = 2e5+10;
int mmax[N], mmin[N];

signed main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int T; cin >> T; while(T--)
    {
        int n, m; cin >> n >> m;
        ll s = (ll)m * n, smax=0, smin=0;
        for(int i = 1; i <= n; i++)
        {
            int a, b; cin >> a >> b;
            s += a - b;
            smin += mmin[i] = max(0, m - b);
            smax += mmax[i] = min(m, a);
        }
        if(s >= 2 * smax)
        {
            cout << s - 2 * smax << '\n';
            for(int i = 1; i <= n; i++)
                cout << mmax[i] << ' ' << m - mmax[i] << '\n';
        }
        else if(s <= 2 * smin)
        {
            cout << 2 * smin - s << '\n';
            for(int i = 1; i <= n; i++)
                cout << mmin[i] << ' ' << m - mmin[i] << '\n';
        }
        else
        {
            cout << s % 2 << '\n';
            for(int i = 1; i <= n; i++)
            {
                int tmp = min((ll)mmax[i] - mmin[i], (s - 2 * smin) / 2);
                smin += tmp;
                tmp += mmin[i];
                cout << tmp << ' ' << m - tmp << '\n';
            }
        }
    }

    return 0;
}