CF #627 div3 E. Sleeping Schedule 题解(dp)

题目链接

题目大意

一个人要睡n次,一天有h个小时,可以选择睡a[ i ]个小时或者a[ i ]-1个小时,起来之后又马上睡。

如果起来的时间在L和R中间(闭区间),则答案加1,求最大的答案。

题目思路

显然是要用dp的思路,但是自己实在太菜,根本不知道怎么用,这次也算学习一下dp吧

进入正题:

显然这个题目答案和前 i 个中有 j 个选减1有关,那么可以设

dp[ i ][ j ] 表示前i个中有j个选择减1

转移方程 dp[ i ][ j ] =max( dp[ i-1 ][ j ],dp[ i - 1 ][ j - 1 ] )+d;

有关d:其中如果前 i 个里面选择 j 个减1的在区间[ L , R ]内,d=1,否则 d=0;

其中方程的意思是如果前 i-1 个中选择了 j 个那么则不选,如果没选则选。

代码

#include
#include
using namespace std;
const int maxn=2e3+5;
int n,h,l,r,a[maxn],d,ans,dp[maxn][maxn];
bool check(int x){
    return l<=(x)%h&&(x)%h<=r;
}
int main(){
    scanf("%d%d%d%d",&n,&h,&l,&r);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        a[i]=a[i]+a[i-1];//前缀和
    }
    for(int i=1;i<=n;i++){//dp[i][j]表示前i个中有j个选择减1
        for(int j=0;j<=i;j++){
            if(check(a[i]-j)){
                d=1;
            }
            else{
                d=0;
            }
            dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+d;
        }
    }
    for(int i=0;i<=n;i++){
        ans=max(ans,dp[n][i]);
    }
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(dp)