[题解] [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; 
}
posted @ 2020-02-11 20:50  ztlztl  阅读(185)  评论(0编辑  收藏  举报