方法一:模拟、贪心、差分
先考虑暴力,由于有区间修改,想到使用差分进行模拟。模拟的时候可以贪心地想到:
若当前的最小值是负数,为了最小化最后的结果,就将后续的所有数全都加上这个负数;若当前的最小值不是负数,那么只找一个数加上,为了方便,就找第一个大于等于它的数即可。
因此需要先对数组a排序,且中间加的过程应该使用差分,边修改边计算,最后遍历到的数a[i]就是答案。
总时间复杂度为O(n * logn),瓶颈主要在排序上,遍历加差分的时间复杂度仅为O(n)。
#include <iostream>
#include <vector>
#include <algorithm>
using i64 = long long;
void solve(){
int n;
std::cin >> n;
std::vector<i64> a(n + 1), diff(n + 3);
for(int i = 1; i <= n; i++){
std::cin >> a[i];
}
std::sort(a.begin() + 1, a.end());
auto update = [&](int l, int r, i64 x){
diff[l] += x;
diff[r + 1] -= x;
};
for(int i = 1; i <= n; i++){
diff[i] += diff[i - 1];
a[i] += diff[i];
if(a[i] < 0){
update(i + 1, n, a[i]);
}else{
update(i + 1, i + 1, a[i]);
}
}
std::cout << a.back() << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int T = 1;
std::cin >> T;
for(int Ti = 0; Ti < T; Ti++){
solve();
}
return 0;
}
方法二:方法一的优化,将差分数组优化成两个变量
cur记录前缀负数的贡献,next记录上一个正数的贡献。
#include <iostream>
#include <vector>
#include <algorithm>
using i64 = long long;
void solve(){
int n;
std::cin >> n;
std::vector<i64> a(n + 1);
for(int i = 1; i <= n; i++){
std::cin >> a[i];
}
std::sort(a.begin() + 1, a.end());
i64 cur = 0, next = 0;
for(int i = 1; i <= n - 1; i++){
i64 val = a[i] + cur + next;
if(val < 0){
cur += val;
next = 0;
}else{
next = val;
}
}
std::cout << a.back() + cur + next << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int T = 1;
std::cin >> T;
for(int Ti = 0; Ti < T; Ti++){
solve();
}
return 0;
}

京公网安备 11010502036488号