Loj 3226 Greedy Pie Eaters

区间 dp.

首先可以假定每个区间都对应了一头牛,没有给出的可以将其牛的重量看作 0 .

当某头牛要吃区间 $[l,r]​$ 时,若剩下的派大于 $1​$ ,可以先让其他牛吃到还剩一个,于是每头牛都恰好吃掉一个派.

设 $f(l,r)​$ 表示把 $l,r​$ 内的派吃完能获得的最大收益,转移时枚举最后被吃的派是 $k​$ ,
$$
f(l,r)=\max_{l\le k\le r} f(l,k-1)+f(k+1,r)+g(l,r,k)
$$
其中 $g(l,r,k)=\max_{l\le x\le k\le y \le r} A_{x,y}$ ,表示用区间不超出 $[l,r]$ 的牛吃掉第 $k$ 个派能获得的最大收益.

转移时考虑 $[l,r]$ 这个区间的贡献就行了.

$$
g(l,r,k)=\max \lbrace A_{l,r},g(l+1,r,k),g(l,r-1,k) \rbrace
$$
时间复杂度 $O(n^3)$ .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//%std
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int out = 0, fh = 1;
char jp = getchar();
while ((jp > '9' || jp < '0') && jp != '-')
jp = getchar();
if (jp == '-')
fh = -1, jp = getchar();
while (jp >= '0' && jp <= '9')
out = out * 10 + jp - '0', jp = getchar();
return out * fh;
}
void print(ll x)
{
if (x >= 10)
print(x / 10);
putchar('0' + x % 10);
}
void write(ll x, char c)
{
if (x < 0)
putchar('-'), x = -x;
print(x);
putchar(c);
}
const int N = 300 + 10;
int n, m, g[N][N][N], a[N][N];
ll f[N][N];
int main()
{
n = read(), m = read();
for (int i = 1; i <= m; ++i)
{
int w = read(), l = read(), r = read();
a[l][r] = w;
}
for (int len = 1; len <= n; ++len)
for (int l = 1; l + len - 1 <= n; ++l)
{
int r = l + len - 1;
for (int k = l; k <= r; ++k)
{
g[l][r][k] = max(a[l][r], max(g[l + 1][r][k], g[l][r - 1][k]));
f[l][r] = max(f[l][r], f[l][k - 1] + f[k + 1][r] + g[l][r][k]);
}
}
write(f[1][n], '\n');
return 0;
}