洛谷P5851 [USACO19DEC]Greedy Pie Eaters P 题解
题目链接:P5851 [USACO19DEC]Greedy Pie Eaters P
题意:
Farmer John 有 M M M 头奶牛,为了方便,编号为 1 , … , M 1,\dots,M 1,…,M。这些奶牛平时都吃青草,但是喜欢偶尔换换口味。Farmer John 一天烤了 N N N 个派请奶牛吃,这 N N N 个派编号为 1 , … , N 1,\dots,N 1,…,N。第 i i i 头奶牛喜欢吃编号在 [ l i , r i ] \left[ l_i,r_i \right] [li,ri] 中的派(包括两端),并且没有两头奶牛喜欢吃相同范围的派。第 i i i 头奶牛有一个体重 w i w_i wi,这是一个在 [ 1 , 1 0 6 ] \left[ 1,10^6 \right] [1,106] 中的正整数。
Farmer John 可以选择一个奶牛序列 c 1 , c 2 , … , c K c_1,c_2,\dots,c_K c1,c2,…,cK,并让这些奶牛按这个顺序轮流吃派。不幸的是,这些奶牛不知道分享!当奶牛 吃派时,她会把她喜欢吃的派都吃掉——也就是说,她会吃掉编号在 [ l c i , r c i ] [l_{c_i},r_{c_i}] [lci,rci] 中所有剩余的派。Farmer John 想要避免当轮到一头奶牛吃派时,她所有喜欢的派在之前都被吃掉了这样尴尬的情况。因此,他想让你计算,要使奶牛按 c 1 , c 2 , … , c K c_1,c_2,\dots,c_K c1,c2,…,cK 的顺序吃派,轮到这头奶牛时她喜欢的派至少剩余一个的情况下,这些奶牛的最大可能体重( w c 1 + w c 2 + … + w c K w_{c_1}+w_{c_2}+\ldots+w_{c_K} wc1+wc2+…+wcK)是多少。
显然是一个区间dp
设 f [ i ] [ j ] f[i][j] f[i][j] 表示吃完 [ i , j ] [i,j] [i,j] 能获得的最大 ∑ w \sum w ∑w
设 g [ k ] [ i ] [ j ] g[k][i][j] g[k][i][j] 表示 k k k 还没吃,准备吃掉 k k k 时 ( i ≤ l d ≤ k ≤ r d ≤ j ) (i \le l_d \le k \le r_d \le j) (i≤ld≤k≤rd≤j) 的最大 w w w
首先不尝试增加奶牛
d
d
d ,即不考虑吃
k
k
k ,有
f
[
i
]
[
j
]
=
max
(
f
[
i
]
[
j
]
,
f
[
i
]
[
k
]
+
f
[
k
+
1
]
[
j
]
)
f[i][j]=\max(f[i][j],f[i][k]+f[k+1][j])
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j])
考虑吃
k
k
k ,尝试增加奶牛
d
d
d ,有
f
[
i
]
[
j
]
=
max
(
f
[
i
]
[
j
]
,
f
[
i
]
[
k
−
1
]
+
f
[
k
+
1
]
[
j
]
+
g
[
k
]
[
i
]
[
j
]
)
f[i][j]=\max(f[i][j],f[i][k-1]+f[k+1][j]+g[k][i][j])
f[i][j]=max(f[i][j],f[i][k−1]+f[k+1][j]+g[k][i][j])
-
关于 g [ k ] [ i ] [ j ] g[k][i][j] g[k][i][j] 如何限制 ( l d ≤ k ≤ r d ) (l_d \le k \le r_d) (ld≤k≤rd)
考虑读入时处理每头奶牛 g [ t ] [ l ] [ r ] = w , l ≤ t ≤ r g[t][l][r]=w,l \le t \le r g[t][l][r]=w,l≤t≤r
-
如何更新 g [ k ] [ i ] [ j ] g[k][i][j] g[k][i][j]
显然当 [ i , j ] = [ l d , r d ] [i,j]=[l_d,r_d] [i,j]=[ld,rd] 时,已经在读入时更新了
当 i ≤ l d i \le l_d i≤ld 或 j ≥ r d j \ge r_d j≥rd 时,我们可以通过
g [ k ] [ i − 1 ] [ j ] = max ( g [ k ] [ i − 1 ] [ j ] , g [ k ] [ i ] [ j ] ) g [ k ] [ i ] [ j + 1 ] = max ( g [ k ] [ i ] [ j + 1 ] , g [ k ] [ i ] [ j ] ) g[k][i-1][j]=\max(g[k][i-1][j],g[k][i][j]) \\g[k][i][j+1]=\max(g[k][i][j+1],g[k][i][j]) g[k][i−1][j]=max(g[k][i−1][j],g[k][i][j])g[k][i][j+1]=max(g[k][i][j+1],g[k][i][j])
进行更新
时间复杂度 O ( n 3 ) O(n^3) O(n3)
代码:
#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(305)
#define M (int)(5e4+15)
int n,m;
int f[N][N],g[N][N][N];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
cin >> n >> m;
for(int i=1,w,l,r; i<=m; i++)
{
cin >> w >> l >> r;
for(int j=l; j<=r; j++)
g[j][l][r]=w;
}
for(int len=1; len<=n; len++)
for(int i=1,j=i+len-1; j<=n; i++,j++)
for(int k=i; k<=j; k++)
{
if(i!=1)g[k][i-1][j]=max(g[k][i-1][j],g[k][i][j]);
if(j!=n)g[k][i][j+1]=max(g[k][i][j+1],g[k][i][j]);
}
for(int len=1; len<=n; len++)
for(int i=1,j=i+len-1; j<=n; i++,j++)
{
for(int k=i; k<j; k++)
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
for(int k=i; k<=j; k++)
f[i][j]=max(f[i][j],(k!=i?f[i][k-1]:0)+(k!=j?f[k+1][j]:0)+g[k][i][j]);
}
cout << f[1][n];
return 0;
}
转载清说明出处