P2990 [USACO10OPEN]Cow Hopscotch G 题解
P2990 [USACO10OPEN]Cow Hopscotch G 题解
题意很简单,感觉可以使用动态规划求解。
先来看一个最暴力的 dp:
令 i 个格子并且返回时跳到第 i - 1 个格子能得到的最大价值之和。
(感觉打得是不是有点复杂了)
应该挺好理解的,其中的
可以发现,上面的
所以就变成了:
其中:
可以把
然后看到 j 的取值范围的左右端点是随 i 的增加单调递增的,于是可以用一个单调递减的单调队列优化掉。
时间复杂度就是
最后的答案就是:
注意
有什么不理解的可以问我 qwq。
Code:
#include <bits/stdc++.h>
#define re register
#define il inline
#define getchar gc
#define fu(i, l, r) for(re int i = l; i <= r; ++i)
using namespace std;
typedef long long ll;
il char gc() {static char ibuf[1 << 20], *p1 = ibuf, *p2 = ibuf; return p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1000010, stdin), p1 == p2) ? -1 : *p1++;}
il void read(re ll& x) {x = 0; re int f = 1; re char ch = getchar(); while(ch < '0' || ch > '9') f *= ((ch == '-') ? -1 : 1), ch = getchar(); while(ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar(); x *= f;}
ll n, k, ans, front = 1, back, v[250001], sum[250001], dp[250001], q[250001];
int main() {
read(n), read(k);
fu(i, 1, n) read(v[i]), sum[i] = sum[i - 1] + max(v[i], 0ll);
dp[1] = v[1];
q[++back] = 0;
fu(i, 2, n) {//dp 和 单调队列优化
while(q[front] < i - k) ++front;
if(front <= back) dp[i] = v[i] + v[i - 1] + dp[q[front]] + sum[i - 2] - sum[q[front]];
while(front <= back && dp[i - 1] - sum[i - 1] >= dp[q[back]] - sum[q[back]]) --back;
q[++back] = i - 1;
}
fu(i, 1, n) ans = max(ans, dp[i] + sum[min(n, i + k - 1)] - sum[i]);
printf("%lld", max(ans, sum[k]));
return 0;
}