CF EDU 120 C - Set or Decrease
阿新 • • 發佈:2022-05-12
C - Set or Decrease
一定是先對最小的元素使用 -1 操作
再從大到小把元素變為最小值
這樣一定是最少操作將序列和減到 k 一下
運算元 = 操作 1 的個數 + 操作 2 的個數,操作 1 可能有很多次,操作 2 是將較大的元素變為最小值,所以可能是 [0, n - 1] 次,所以可以列舉操作 2 的個數
推公式
先對 a 陣列從大到小排序,求出字首和,設操作 2 有 i 次,就是將前 i 大的元素變為最小值,設操作 1 有 t 步
設一共要減少 sub = s[n] - k
- a[n] -> a[n] - t
- s[i] -> i * (a[n] - t)
所以這種情況減少了 t + s[i] - i * (a[n] - t) >= sub -> \(t >= \frac {sub + i*a[n]-s[i]}{i+1}\)
求出最小的 t,這種情況的答案就是 t + i
注意 t 可能小於 0,要令 t = max(t, 0)
列舉 i 求出最小值即可
#include <iostream> #include <cstring> #include <algorithm> #include <vector> #include <cmath> using namespace std; typedef long long ll; const int N = 2e5 + 10; int n; ll a[N], s[N], k, sub; int main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int T; cin >> T; while(T--) { cin >> n >> k; for (int i = 1; i <= n; i++) cin >> a[i]; sort(a + 1, a + n + 1, greater<ll>()); for (int i = 1; i <= n; i++) s[i] = s[i-1] + a[i]; ll sub = s[n] - k; if (sub <= 0) { cout << 0 << endl; continue; } if (n == 1) { cout << sub << endl; continue; } ll ans = 1e18; for (int i = 0; i < n; i++) { ll t = (sub + i * a[n] - s[i] + i) / (i + 1); t = max(t, 0ll); ans = min(ans, t + i); } cout << ans << endl; } return 0; }
二分
關鍵思路相同,更好寫一點
#include <iostream> #include <cstring> #include <algorithm> #include <vector> #include <cmath> using namespace std; typedef long long ll; const int N = 2e5 + 10; int n; ll a[N], s[N], k, sub; bool check(ll x) { for (int i = 0; i <= min(x, n - 1ll); i++) { ll minn = a[n] - (x - i); ll sum = i * minn + s[n-1] - s[i] + minn; if (sum <= k) return true; } return false; } int main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int T; cin >> T; while(T--) { cin >> n >> k; for (int i = 1; i <= n; i++) cin >> a[i]; sort(a + 1, a + n + 1, greater<ll>()); for (int i = 1; i <= n; i++) s[i] = s[i-1] + a[i]; ll sub = s[n] - k; if (sub <= 0) { cout << 0 << endl; continue; } if (n == 1) { cout << sub << endl; continue; } ll l = 0, r = 1e18; while(l + 1 != r) { ll mid = l + r >> 1; if (check(mid)) r = mid; else l = mid; } cout << r << endl; } return 0; }