Codeforces Round #627 (Div. 3)

Posted wizarderror

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #627 (Div. 3)相关的知识,希望对你有一定的参考价值。

Contest Info


Practice Link

SolvedABCDEF
5/6 O O O  O  Ø  
  • O 在比赛中通过 
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


E.Sleeping Schedule

题意:

在这个故事中,一天有$h$小时,在$[l;r]$之间入睡就能做个好梦。

现在我从$0$时刻开始,第$i$次要睡觉的时候,我都可以选择$a[i]$或者$a[i]-1$小时后入睡,问睡了$n$次觉的最大好梦数

思路:

这是个典型的基础$dp$问题,然而比赛时候我的思路和定义的状态、转移极为混乱

题解给出一种比较好的做法,我们用$dp[i][j]$表示睡$i$次觉并执行$j$次$-1$操作时睡好觉的最大次数

类似于背包$dp$,假如我们选择提前入睡,那么$dp[i][j]$就由$dp[i-1][j-1]$得到;我们不选择提前入睡,$dp[i][j]$就由$dp[i-1][j]$转移而来,由此可以得到状态转移方程:

$$dp[i][j] = max(dp[i-1][j-1], dp[i-1][j])+lleq (sum[i]-j)\%h leq r$$

需要注意的一点是,当$j$为$0$的时候,很明显当前只能不选择提前入睡

技术图片
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int maxn = 2e3+100;
int n, h, l, r, ans;
int a[maxn], dp[maxn][maxn];
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-1]; 
    for(int i = 1; i <= n; i++){
        for(int j = 0; j <= i; j++){
            int t = (a[i]-j)%h;
            if(j) dp[i][j] = max(dp[i-1][j], dp[i-1][j-1])+(l<=t&&t<=r);
            else dp[i][j] = dp[i-1][j]+(l<=t&&t<=r);
        }
    }
    for(int i = 0; i <= n; i++) ans = max(ans, dp[n][i]);
    printf("%d", ans);
}
View Code

还有一种做法类似于我比赛的时候的做法,我们用$dp[i][j]$表示睡$i$次觉,第$i$次入睡时间为$j$时的最大好梦数

这个转移非常好理解,$dp[i][j]$也是由当前是否提前入睡来转移:

$$dp[i][j] = max(dp[i-1][(j-a[i]+h)\%h], dp[i-1][(j-a[i]+1+h)\%h])+(lleq jleq r)$$

重点在于,我们要避免不合法的转移!!!

也就是说除了$dp[0][0] = 0$外,我们要把$dp$的值设置为$-inf$,原因在于我们开始没有睡觉的时候是从$0$时刻开始的,不可能从其他时刻开始,就应该把其他时刻设置为不合法的情况即$-inf$

那你可能会有疑惑,为什么上面那种我不需要这样呢?那是因为我状态的定义决定了当前转移所需要的状态的都是合法的

技术图片
#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 2e3+100;
int n, h, l, r, ans;
int a[maxn], dp[maxn][maxn];
int main(){
    scanf("%d%d%d%d", &n, &h, &l, &r);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    memset(dp, -0x3f, sizeof(dp));
    dp[0][0] = 0;
    for(int i = 1; i <= n; i++){
        for(int j = 0; j < h; j++){
            dp[i][j] = max(dp[i-1][(j-a[i]+h)%h], dp[i-1][(j-a[i]+1+h)%h])+(l<=j&&j<=r);
        }
    }
    for(int i = 0; i < h; i++) ans = max(ans, dp[n][i]);
    printf("%d", ans);
}
View Code

 

 

 

 

 

 

以上是关于Codeforces Round #627 (Div. 3)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #627 (Div. 3) 补题

Codeforces Round #627 (Div. 3)

Codeforces Round #627 (Div. 3)(A--D)

Codeforces Round #627 (Div. 3) D. Pair of Topics(二分/直接遍历)

Codeforces Round #627 (Div. 3)F. Maximum White Subtree

Codeforces Round #627 (Div. 3) F - Maximum White Subtree(深度优先搜索)