SP283 NAPTIME - Naptime

与这一题而言,我们需要解决一些问题:

  • 每一小时都接在前一小时后面,而当前能否获得体力值依赖于前一小时是否睡觉,这引出了一个环形的依赖关系问题

解决方案:将环斩成链,用区间DP处理链上的问题,

- 在1的基础下,又会有新的问题:
从哪里斩开?

解决方案:从两天中间,也就是n时与0时的这个点上斩开

- 定义状态

dp[i][j] 在一天的前i个小时中睡了j小时
但我们会发现这项定义是有问题的,因为题目中提到,在单独的一段睡眠中,第一个小时不能恢复体力
所以我们要再pick一个维度,[0,1],代表dp[i]的第i个小时是否睡觉,那这样,我们就可以很好的兼顾这个情况

  • 状态转移
    $ dp[i][j][0] = max(dp[i - 1][j][0],dp[i - 1][j][1])$
    当然,当第i小时未睡觉时,也没法get到这个时间段的体力值,只能从i - 1处睡j小时转移而来。
    $ dp[i][j][1] = max(dp[i - 1][j - 1][0],dp[i - 1][j - 1][1] + u[i]); \( 当第i个小时睡了觉时, \){\color{red} {表达式} }$
#include<bits/stdc++.h>
using namespace std;huodetilizhi
const int maxn = 3900;
const int maxm = 3900;
int T;
int dp[maxn][maxm][2] = {0};
int u[maxm],n,b,ans;
void Fdp(){
	for(int i = 2;i <= n;i ++){
		for(int j = 0;j <= min(i,b);j ++){
                        dp[i][j][0] = max(dp[i - 1][j][0],dp[i - 1][j][1]);			
                        if(j >= 1){
				dp[i][j][1] = max(dp[i - 1][j - 1][0],dp[i - 1][j - 1][1] + u[i]);  
			} 
		}
	}
}
void work(){
	cin >> n >> b;
	ans = -1e9;
	if(b == 0){cout << "0" << endl;return;}
	memset(dp,0xcf,sizeof(dp));
	for(int i = 1;i <= n;i ++){
		cin >> u[i];
	}
	dp[1][0][0] = 0;
	dp[1][1][1] = 0;
	Fdp();
	ans = max(dp[n][b][0],dp[n][b][1]);
	memset(dp,0xcf,sizeof(dp));
	dp[1][0][0] = 0;
	dp[1][1][1] = u[1];
	Fdp();
	ans = max(ans,dp[n][b][1]);
	cout << ans << endl;
	return ;
}
int main(){
	cin >> T;
	while(T --){
		work();
	}
	return 0;
}
posted @ 2019-07-26 12:12  永远_少年  阅读(214)  评论(0)    收藏  举报