• 选择一个 $i$,replace $a_i$ with $\lceil \frac{a_i}{2} \rceil$
  • 选择一个 $i$,replace $a_i$ with $\max(a_i - b, 0)$

每个 $i$ 最多进行一次相同的操作。

sol1

https://codeforces.com/contest/1799/submission/218644087

随机下标之后在期望选择数量附近 $dp$(这样正确率有保证),复杂度是 $O(K^2N)$,K 为在附近取多少个。

sol2

https://codeforces.com/contest/1799/submission/221053633

考虑三分同时两种操作的个数,这个显然是一个凸函数。

可以采用 $agc018c$ 的 L-convex 的做法来做。

https://web.archive.org/web/20220813122625/https://opt-cp.com/agc018c-lconvex/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <bits/stdc++.h>
using namespace std;
const long long INF_INT = 1000000000;
const long long INF = 1000000000000000000;
//https://web.archive.org/web/20220813122625/https://opt-cp.com/agc018c-lconvex/
template<class TD, class TR, TR (*f)(vector<TD>)>
struct Lconvex {
int n;
Lconvex(int _n) : n(_n) {}
pair<TR, vector<TD>> min_scaling(vector<TD> x, TD alpha) const {
TR f0, f1 = f(x);
while (alpha) {
f0 = f1, f1 = min_cube(x, f0, alpha);
if (f0 == f1) alpha >>= 1;
}
return {f1, move(x)};
}
private:
TR min_cube(vector<TD> &x, TR f_best, const TD alpha) const {
vector<TD> x0{x};
for (int S = 1; S < (1 << n) - 1; S++) {
vector<TD> xS{x0};
for (int i = 0; i < n; i++) if (S >> i & 1) xS[i] += alpha;
TR fS = f(xS);
if (fS < f_best) f_best = fS, x = move(xS);
}
return f_best;
}
};
int n;
array<int, 4> x;
vector<array<int, 4>> c;

long long f(vector<int> q) {
long long res = 0;
for (int i = 0; i < n; i++) res += max({c[i][0] - q[0], c[i][1] - q[1], c[i][2] - q[2], c[i][3] - q[3]});
for (int j = 0; j < 4; j++) res += (long long) x[j] * q[j];
return res;
}
int main() {
int t;
cin >> t;
for (int i = 0; i < t; i++){
int b, k1, k2;
cin >> n >> b >> k1 >> k2;
vector<int> a(n);
for (int j = 0; j < n; j++){
cin >> a[j];
}
c.resize(n);
auto solve = [&](int A){
x[0] = n + A - k1 - k2;
x[1] = k1 - A;
x[2] = k2 - A;
x[3] = A;
for (int j = 0; j < n; j++){
c[j][0] = a[j];
c[j][1] = (a[j] + 1) / 2;
c[j][2] = max(a[j] - b, 0);
c[j][3] = min(max((a[j] + 1) / 2 - b, 0), (max(a[j] - b, 0) + 1) / 2);
}
for (int j = 0; j < n; j++){
for (int k = 0; k < 4; k++){
c[j][k] = INF_INT - c[j][k];
}
}
Lconvex<int, long long, f> lc(4);
return INF_INT * n - lc.min_scaling({0, 0, 0, 0}, 1 << 29).first;
};
int L = max(k1 + k2 - n, 0), R = min(k1, k2);
long long ans = min(solve(L), solve(R));
while (R - L > 2){
int ml = (L + R) / 2;
int mr = ml + 1;
long long sl = solve(ml);
long long sr = solve(mr);
ans = min({ans, sl, sr});
if (sl > sr){
L = ml;
} else {
R = mr;
}
}
ans = min(ans, solve((L + R) / 2));
cout << ans << endl;
}
}

这个 L-convex 可以当黑盒来用。

使用方法结合题目,f 函数里面使用了线性规划对偶。