hodf 快乐题
(前置:这篇题解中不区分“菜地”“菜田”“点”等名词,偏意识流,建议感性理解。)
首先我们考虑
当
当
(不过实际上
那么接下来我们来考虑
-
一片菜地只会被打一枪。
-
不存在相邻的两片菜地都被打枪了。
首先,在
否则的话,欲证明之,我们试图去证明之前我们分析
我们考虑反之,
(以上是作者的证明心路,可能比较意识流,但看得懂就行=.=)
然后有了这两条,我们就可以设计 DP 了:
设
这个东西的转移非常显然,如果没打,那就枚举上一个点打没打;如果打了,就枚举上一枪在不在
但这会有一个问题:第
代码很好写。但有个细节:不合法状态要设成 memset 0xc0 实现),而不是
代码参考:
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 4009;
int dp[2][2][N];
int DP(int* r, int n, int k) {
memset(dp, 0xc0, sizeof dp);
memset(dp[0][0], 0, sizeof dp[0][0]);
for (int i = 1; i <= k; ++i)
for (int j = 2; j <= n; ++j)
dp[i & 1][0][j] = max(dp[i & 1][0][j - 1], dp[i & 1][1][j - 1]),
dp[i & 1][1][j] =
max(dp[~i & 1][0][j - 1], dp[~i & 1][1][j - 2] + r[j - 1]) +
r[j];
return max(dp[k & 1][0][n], dp[k & 1][1][n]);
}
int n, k, r[N];
int main() {
cin >> n >> k;
for (int i = 1; i <= n; ++i) cin >> r[i];
int ans;
if (!k)
ans = 0;
else if ((k << 1) >= n)
ans = accumulate(r + 1, r + n + 1,
n == 3 && k == 2 ? -*min_element(r + 1, r + n + 1) : 0);
else
ans = DP(r, n, k), r[n - 1] += r[n],
ans = max(ans, DP(r + 1, n - 2, k - 1) + r[1]);
return cout << ans << endl, 0;
}
以上。