题解:CF727F Polycarp's problems

· · 题解

题意

给定一个长为 n 的数列 am 次询问,每次给出 a_0 的值,求至少删去多少个数使任意位置的前缀和不为负数。

思路

f_{i,j}表示前 i 个数,保留 j 个数后的最大数。

则可得

f_{i,j} = \min(f_{i + 1,j}, \max(0,f_{i+1,j-1}-a_i)) + 选择第 $i$ 个数不取,则 $$f_{i,j} = f_{i+1,j}$$ + 选择第 $i$ 个数取,则 $$f_{i,j} = f_{i+1,j-1}-a_i$$ 但我们还得要让前缀和不为负数,所以要对 $0$ 取 $\max$。 最后,我们再倒序枚举 $f_{1,x}$, 然后输出 $n-i$ 即可。 ### 代码如下 ```cpp #include<bits/stdc++.h> #define int long long using namespace std; #define rep(i, l, r) for(int i = l; i <= r; ++ i) #define per(i, r, l) for(int i = r; i >= l; -- i) const int N = 200010, M = 2010; int a[N]; int f[M][M]; int n, m, x; main() { scanf("%lld%lld", &n, &m); rep(i, 1, n) scanf("%lld", &a[i]); memset(f, 0x3f, sizeof f); f[n + 1][0] = 0; per(i, n, 1) { rep(j, 1, n - i + 1) f[i][j] = min(f[i + 1][j], max(0ll, f[i + 1][j - 1] - a[i])); f[i][0] = 0; } for(; m; -- m) { scanf("%lld", &x); per(j, n, 0) if(f[1][j] <= x) { printf("%lld\n", n - j); break; } } } ```