题面
题意
给你一个长度为n的序列a,你的初始生命值为0,你可以选择加上ai,但前提是保证在任何时刻生命值不小于0. 求最多能加多少个值。C1版本的的n为2000,C2版本的n为20000
C1题解
C1的n只有2000,可以直接用dp来做,f[i] [j] 表示在前 i 瓶中选择了 j 瓶的最大价值,就可以由 max ( f[i-1] [j] , f[i-1] [j] +a[i] ) 得到
C1代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2005;
const ll INF = 1e15;
int n;
ll a[N];
ll f[N][N]; //在前 i 瓶种选择了 j 瓶的最大价值
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
for (int j = 1; j < i; j++) {
f[i][j] = max(f[i - 1][j - 1] + a[i], f[i - 1][j]);
if (f[i][j] < 0) f[i][j] = -INF; //小于0直接赋值无穷大,防止下次更新为正数
}
f[i][i] = f[i - 1][i - 1] + a[i];
if (f[i][i] < 0) f[i][i] = -INF;
}
int res = 0;
for (int i = 0; i <= n; i++) {
if (f[n][i] >= 0) res = i;
}
cout << res << endl;
return 0;
}
C2题解
c2版本的n为20000,dp会超时,考虑贪心,我们用一个小根堆来维护已经选的值,当加入一个值使得总和小于0,那么就删去堆顶元素,直到值不小于0,每次取堆的长度就是所能选的最大长度
C2代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
ll n;
ll a[N];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
priority_queue<int, vector<int>, greater<int>> p;
int ans = 0;
ll sum = 0;
for (int i = 1; i <= n; i++) {
p.push(a[i]);
sum += a[i];
while (sum < 0) {
sum -= p.top();
p.pop();
}
ans = max(ans, (int) p.size());
}
cout << ans << endl;
return 0;
}