D1
分情况讨论。
-
k ≤ n k\le n k≤n 时,
我们容易想到给一个位置不断地更新,但是这样明显不是最优解,那么,我们可以利用题目所给的每一个的初始红色。
先把数组从小到大进行排序,再从前往后依次给 a i a_i ai 加上 k , k − 1 … 2 , 1 k,k-1\ldots 2,1 k,k−1…2,1,最后扫一遍求出最大值,时间复杂度 O ( n log n ) O(n\log n) O(nlogn)。
-
k > n k>n k>n 时,
先消耗 n n n 次操作,对其按照 k ≤ n k\le n k≤n 的做法更新,此时所有位置都是蓝色的。
我们对每个数做偶数次操作,每两次操作 + 1 +1 +1,最后可能剩下一个操作(减),我们把它丢给最大的,再计算最大值。
时间复杂度为 O ( n log n + n q ) O(n\log n+nq) O(nlogn+nq)。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e4 + 10;
int n, q;
int a[maxn];
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> q;
for (int i = 1; i <= n; ++i) cin >> a[i];
sort(a + 1, a + n + 1);
while (q--) {
int s = 0, x, ans = 1e18;
cin >> x;
for (int i = 1; i <= n; ++i) {
if (!x) {
ans = min(ans, a[i]);
continue;
}
if (i == n) {
if (x & 1) {
s += a[i] + x;
ans = min(a[i] + x, ans);
x--;
s -= x / 2;
ans = min(ans, s / n);
} else {
s += a[i] - x / 2;
ans = min({ans, a[i], s / n});
}
} else ans = min(ans, a[i] + x), s += a[i] + x;
if (x != 0) x--;
}
cout << ans << ' ';
}
}
D2
针对 k > n k>n k>n 的情况进行优化,如果 k − n k-n k−n 是偶数,那就要减 k − n 2 \dfrac{k-n}{2} 2k−n,如果是奇数,就减 k − n + 1 2 \dfrac{k-n+1}{2} 2k−n+1,时间复杂度 O ( 1 ) O(1) O(1)。
最终的时间复杂度就是 O ( n log n + q ) O(n\log n+q) O(nlogn+q)。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 3e5 + 20;
int n, q, s, x, o, ans;
int a[maxn], f[maxn];
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> q;
for (int i = 1; i <= n; ++i) cin >> a[i], s += a[i];
sort(a + 1, a + n + 1);
fill(f + 1, f + n + 10, 1e18);
for (int i = 1; i <= n; ++i) f[i + 1] = min(f[i], a[i]) + 1;
while (q--) {
cin >> x;
if (x < n) cout << min(f[x + 1], a[x + 1]) << ' ';
else {
ans = 0, o = s;
if (!((x - n) & 1)) {
ans = f[n + 1] + x - n;
o += n * (x * 2 - n + 1) / 2 - (x - n) / 2;
} else {
ans = min(f[n] + x - n + 1, a[n]);
o += (n - 1) * (x * 2 - n + 2) / 2 - (x - n + 1) / 2;
}
cout << min(ans, o / n) << ' ';
}
}
}