[题解] [JSOI2014] 打兔子
题面
题解
最优方案下相邻两个坑肯定不会同时开枪
那如果是链就很好做了
环呢?
讨论一下 1 和 n 谁开枪谁不开枪就行
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
const int N = 4005;
using namespace std;
int n, m, a[N << 1], b[N], f[N][N][2], ans, sum;
template < typename T >
inline T read()
{
T x = 0, w = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w;
}
void dp()
{
for(int i = 2; i <= n; i++)
for(int j = 0; j <= m; j++)
{
f[i][j][0] = max(f[i - 1][j][0], f[i - 1][j][1]);
if(j) f[i][j][1] = max(f[i - 1][j - 1][0], f[i - 2][j - 1][1] + a[i - 1]) + a[i];
}
}
int calc1()
{
for(int i = 0; i <= n; i++)
for(int j = 0; j <= m; j++)
f[i][j][0] = f[i][j][1] = -0x3f3f3f3f;
f[1][0][0] = 0, dp();
return max(f[n][m][0], f[n][m][1]);
}
int calc2()
{
int tmp = a[n]; a[n - 1] += tmp, a[n] = 0;
for(int i = 0; i <= n; i++)
for(int j = 0; j <= m; j++)
f[i][j][0] = f[i][j][1] = -0x3f3f3f3f;
f[1][1][1] = a[1], dp(), a[n] += tmp, a[n - 1] -= tmp;
return f[n][m][0];
}
int main()
{
n = read <int> (), m = read <int> ();
for(int i = 1; i <= n; i++)
sum += (a[i] = read <int> ());
if(m >= (n + 1) / 2)
{
if(n == 3 && m == 2)
printf("%d\n", sum - min(min(a[1], a[2]), a[3]));
else printf("%d\n", sum);
return 0;
}
ans = max(calc1(), calc2());
reverse(a + 1, a + n + 1);
ans = max(ans, calc2());
printf("%d\n", ans);
return 0;
}