CF2013D 题解
提供一个二分做法。
因为当 \(a_i > a_{i + 1}\) 是做操作是不劣的,所以最终 \(a\) 一定单调不降。那么我们二分一个最小的 \(\max(a_i)\) 和最大的 \(\min(a_i)\),答案就是 \(\max(a_i) - \min(a_i)\)。
下面说一下如何 check,以 \(\max(a_i)\) 举例。设当前二分到 \(M\),check 的时候要把 \(> M\) 的元素变小。于是可以计算出最少要 \(-1\) 多少次,把它与最多能 \(+1\) 多少次比较,即可进行 check。
#include <iostream>
#include <ranges>
#include <vector>
using namespace std;
using i64 = long long;
constexpr i64 V = 1e12;
struct Solution {
vector<i64> a;
bool check_min(i64 mn)
{
i64 minus = 0, add = 0;
for (auto x : a) {
if (x > mn)
minus += x - mn;
else
add += mn - x;
if (minus < add)
return false;
}
return true;
}
bool check_max(i64 mx)
{
i64 minus = 0, add = 0;
for (auto x : a | views::reverse) {
if (x < mx)
add += mx - x;
else
minus += x - mx;
if (minus > add)
return false;
}
return true;
}
void main()
{
int n;
cin >> n;
a.resize(n);
for (auto& x : a)
cin >> x;
i64 l = 1, r = V;
while (l < r) {
i64 mid = (l + r + 1) >> 1;
if (check_min(mid))
l = mid;
else
r = mid - 1;
}
i64 mn = l;
l = 1;
r = V;
while (l < r) {
i64 mid = (l + r) >> 1;
if (check_max(mid))
r = mid;
else
l = mid + 1;
}
i64 mx = l;
cout << mx - mn << '\n';
}
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t = 1;
cin >> t;
while (t-- > 0)
Solution().main();
return 0;
}

浙公网安备 33010602011771号