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;
}

猜你喜欢

转载自www.cnblogs.com/yangxuejian/p/11249484.html
今日推荐