Least Prefix Sum
思路 (贪心 + 优先队列)
设\(p_i = \sum\limits_{i=1}^n a_i\),设x,\(p_x < p_m\), 且\(1 \le x < m\), 则\(p_x - p_m\) 为两者的大小关系,显然若满足该关系应该保证\(\sum\limits_{i=x+1}^m a_i \le 0\), 我们采取贪心的策略每次挑选一个区间\([x+1, m]\)的最大值,当且仅当\(p_x - p_m \le 0\)时,所需要的操作数最少,因为\(p_m\)的值非递增,我们保证该策略为最优策略, 对于\(m < x \le n\) 同理。
复杂\(O(nlogn)\)
Code
#include <iostream>
#include <vector>
#include <queue>
#define rep(i, j, n) for (int i = j; i <= n; i ++)
#define per(i, j, n) for (int i = j; i >= n; i --)
using namespace std;
void solve() {
int n, m, ans = 0; cin >> n >> m;
vector<long long> a(n + 1), pre(n + 1, 0);
for (int i = 1; i <= n; i ++) {
cin >> a[i];
pre[i] = pre[i - 1] + a[i];
}
priority_queue<long long> h;
long long curr = 0;
per (i, m, 2) {
if (a[i] > 0) h.push(a[i]);
curr += a[i];
while (curr > 0) {
int x = h.top(); h.pop();
curr -= 2 * x, ans ++;
}
}
while (h.size()) h.pop();
curr = 0;
rep (i, m + 1, n) {
if (a[i] < 0) h.push(-a[i]);
curr += a[i];
while (curr < 0) {
int x = h.top(); h.pop();
curr += 2 * x;
++ ans;
}
}
cout << ans << "\n";
}
int main() {
int _; cin >> _;
while (_ --) {
solve();
}
}