题目描述
在某个星球上,一天由
N
个小时构成,我们称
为了身体健康,这头牛希望遵循生物钟,每天采用相同的睡觉计划。另外,由于时间是连续的,即每一天的第
N
个小时和下一天的第
请你帮忙给这头牛安排一个睡觉计划,使它每天恢复的体力最多。
输入
- 第一行为两个数,
N 和 B 。 - 下面为
N+1 行,每行包含一个数字: Ui 。0≤Ui≤200000,2≤B<N,3≤N≤3830
输出
- 可恢复的最大能量值。
样例输入
5 3
2
0
3
1
4样例输出
6
提示
牛在第 4 小时开始入睡,未睡着。
在第5、6 小时已经入睡,得到 2+4=6 的能量。Sol
Easy Ver.
先来考虑一下简化的问题:第 N 个小时和下一天的第一个小时不是连着的。
f[i][j][1]
表示前i 个小时共休息了j小时,现在正在休息,累计恢复的体力的最大值。
f[i][j][1]
表示前 i 个小时共休息了j小时,现在不在休息,累计恢复的体力的最大值。
注意:i包括现在。
可知:
f[i,j,0]=max(f[i−1,j,0],f[i−1,j,1])f[i,j,1]=max(f[i−1,j−1,0],f[i−1,j−1,1]+U[i])
1. f[i−1,j,0] 为现在不休息,且上个小时也不休息。
2. f[i−1,j,1] 为现在不休息,上个小时休息了。
3. f[i−1,j−1,0] 为现在休息,上个小时没休息(刚休息不加能量)。
4. f[i−1,j−1,1]+U[i] 为现在休息,上个小时已经休息了(加能量)。
这时的答案应该是:
ans=max(f[N.B,1],f[N,B,0])
除了 f[1,0,0]=0 外,其他的全设为 −∞ 。Original Mode
这个简化的问题与原问题的差别:
可能漏掉了第 N 个小时和第1 个小时休息恢复的体力。
可以考虑一下2种情况:
1. 1时休息,N时不休。
2. 1时休息,N时也休。综上所述(边界条件)
- (1)第一段不睡,这样最后一段睡不睡都无所谓:
边界为:f[1][0][0] = 0, f[1][1][1] = -INF
( f[1,0,0]为在1时不休息;f[1,1,1]在这里不合理 )
结果为:max(f[N][B][0], f[N][B][1])
- (2)第一段睡,最后一段也睡:
边界为:f[1][1][1] = utility[1], f[1][0][0] = -INF
( f[1,1,1]为在1时已经休息且不是第一小时;f[1,0,0]为在第1小时没休息,不合理 )
结果为:f[N][B][1]
- (3)第一段睡,最后一段不睡:
边界为:f[1][1][1] = 0, f[1][0][0] = -INF
( f[1,1,1]为在1时已经休息且是第一小时;f[1,0,0]为在第1小时没休息,不合理 )
结果为:f[N][B][0]
初始化的问题
- 不能全部把
F[][][]
都设定为-INF
:因为f[i][0][0]
都被置为-INF
,即意味着“前i小时都不睡是不可能发生的”,然而是可以最后几个小时休息的。 - 不能全部把
F[][][]
都设定为0
:因为像f[i][0][1]
这样的状态(共睡了0小时,现在正在休息)是不可能发生的,所以必须置为-INF
。 - 解决方法:先全部置为
-INF
,设定边界条件,然后在每次循环前把f[i][0][0]
置为0。
要注意的问题
由于N的范围是 N∈[3,3830] ,B的范围是 B∈[2,N) ,这样数组至少是 3830∗3830∗2 ,空间复杂度过高。
鉴于第 i 段只与第i−1 段有关,所以果断用滚动数组,这样就变成了2*3830*2,明显下降不少了。代码
#include <cstdio> #include <cstring> #include <cctype> #include <algorithm> #define __INITIALIZE memset(f, 0xc0c0c0c0, sizeof f) #define rep(i, j, k) for (int i = j; i <= k; i++) using namespace std; inline int read() { int r = 0; char cc = getchar(); while (!isdigit(cc)) cc = getchar(); while (isdigit(cc)) { r = r * 10 + cc - 48; cc = getchar(); } return r; } int n, b; int f[2][3831][2]; int r[3831]; int temp[3]; void solve() { rep (i, 2, n) { f[i % 2][0][0] = 0; rep (j, 1, b) { f[i % 2][j][0] = max(f[(i - 1) % 2][j][0], f[(i - 1) % 2][j][1]); f[i % 2][j][1] = max(f[(i - 1) % 2][j - 1][1] + r[i], f[(i - 1) % 2][j - 1][0]); } } } int main(int argc, char **argv) { n = read(); b = read(); for (int i = 1; i <= n; i++) { r[i] = read(); } //1 awake __INITIALIZE; f[1][0][0] = 0; f[1][1][1] = 0xc0c0c0c0; solve(); temp[0] = max(f[n % 2][b][1], f[n % 2][b][0]); //1 sleep, n awake __INITIALIZE; f[1][0][0] = 0; f[1][1][1] = 0; solve(); temp[1] = f[n % 2][b][0]; //1 sleep, n sleep __INITIALIZE; f[1][1][1] = r[1]; f[1][0][0] = 0xc0c0c0c0; solve(); temp[2] = f[n % 2][b][1]; printf("%d", max(max(temp[0], temp[1]), temp[2])); }