cf1607 G. Banquet Preparations 1(貪心)
阿新 • • 發佈:2021-11-13
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\)
如果 \(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; }