CF-div3-627-E. Sleeping Schedule| dp
思路
状态转移方程
dp[i][j] 表示第i个位置,在时间为j下的 好睡眠次数
dp[i-1][j] 可以推出 dp[i][j+a[i]] 和 dp[i][j+a[i]-1];
l,r时间段内:dp[i][u] = max(dp[i][u],dp[i-1][j] + 1); // u表示 j-a[i] 或者 j-(a[i]+1)
非l,r时间内:dp[i][u] = max(dp[i][u],dp[i-1][j]);
另外dp[i][j]初值设置为-1,因为前一时刻dp[i-1][j]下在j时刻可能未醒来,即前一个状态未到达,那么当前状态也不可能到达了
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2100;
int a[maxn];
int dp[maxn][maxn];
int n,h,l,r;
int main(){
cin>>n>>h>>l>>r;
for(int i=1;i<=n;i++){
cin>>a[i];
}
//判断是否经历过dp[i-1][j] 没经历过肯定不可退出下一阶段
memset(dp,-1,sizeof dp); //表示当前状态下未醒来:有状态是无法达到的 设置初态为-1未到达过
dp[0][0] = 0; //只能由初状态得来
for(int i=1;i<=n;i++){
for(int j=0;j<h;j++){
if(dp[i-1][j] == -1) continue; //没到达过i-1,j肯定不可推当当前
int u = (j + a[i])%h;
int v = (j + a[i] - 1)%h;
if(u>=l && u<=r){
dp[i][u] = max(dp[i][u],dp[i-1][j] + 1);
}else dp[i][u] = max(dp[i][u],dp[i-1][j]);
if(v>=l && v<=r){
dp[i][v] = max(dp[i][v],dp[i-1][j] + 1);
}else dp[i][v] = max(dp[i][v],dp[i-1][j]);
}
}
int ans = 0;
for(int j=0;j<h;j++){
ans = max(ans,dp[n][j]);
}
cout<<ans;
}