CodeForces Round#627 E. Sleeping Schedule

原题链接

题目E
题意

每天有 h h h 个小时,定义一个 g o o d good good 的概念:入睡时间在 [ l , r ] [l,r] [l,r] 范围内 ( 0 ≤ l ≤ r < h ) (0≤l≤r<h) (0lr<h)
给出睡觉次数 n n n n n n 个正整数 a 1 , a 2 , a 3 , . . . a n a_1,a_2,a_3,...a_n a1,a2,a3,...an ,代表第 i i i 次睡觉需等待的时间,这个时间可以选择 a i a_i ai a i − 1 a_i-1 ai1 。起始时间 t = 0 t=0 t=0
现在针对以上输入,求出 n n n 次睡觉时间中尽可能多的满足 g o o d good good的次数。

思路

我们要知道每次睡觉的时间是多少,判断在不在范围里。但是考虑 n n n 次选择的复杂性,每次都有两种情况,暴力解决时间复杂度很大,所以是动态规划的思路。 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示当第 i i i 次入睡时间是 j j j 时,此时 g o o d good good 的最多次数。
下面讨论的时间都是对 h h h 取模后的时间,都在 [ 0 , h ) [0,h) [0,h) 。在第 i i i 次做选择时,对所有可能的入睡时间 t i t_i ti 来说(对 t i t_i ti 的取值进行遍历),上一次的入睡时间 t t t ( t i − a i + h ) % h (t_i-a_i+h)\%h (tiai+h)%h 或者 ( t i − ( a i − 1 ) + h ) % h (t_i-(a_i-1)+h)\%h (ti(ai1)+h)%h ,可以直接使用已知结果 d p [ i − 1 ] [ t ] dp[i-1][t] dp[i1][t] ,再加上对 t i t_i ti 的判断。
复杂度是 O ( n ∗ h ) O(n*h) O(nh)

代码
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 2020;
const int MAX_H = 2020;

int n,h,l,r;
int a[MAX_N];
int dp[MAX_N][MAX_H];
int ans;

int main(){
    cin >> n >> h >> l >> r;
    for(int i=1;i<=n;i++)   cin >> a[i];

    for(int i=1;i<=n;i++){
        for(int j=0;j<h;j++){
            dp[i][j]=-MAX_N;
        }
    }
    if(a[1]>=l&&a[1]<=r)    dp[1][a[1]]=1;
    else    dp[1][a[1]]=0;
    if(a[1]>=l+1&&a[1]<=r+1)    dp[1][a[1]-1]=1;
    else    dp[1][a[1]-1]=0;
    for(int i=2;i<=n;i++){
        for(int j=0;j<h;j++){
            int p=j-a[i];
            int q=j-a[i]+1;
            if(p<0) p+=h;
            if(q<0) q+=h;
            int d=0;
            if(j>=l&&j<=r)  d=1;
            dp[i][j]=max(dp[i-1][p]+d,dp[i-1][q]+d);
        }
    }
    for(int j=0;j<h;j++){
        ans=max(ans,dp[n][j]);
    }
    cout << ans;
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值