Codeforces Round #627 (Div. 3)

好久没写博客了。。。。。在家的学习效率太低了,啥时候能开学啊啊啊啊啊!!
E. Sleeping Schedule
题意 一个人 每次睡觉都是一天 然后每天有h小时
然后每天睡n次 每一次醒来都有过a[i] 或 a[i]-1小时后在睡,问 在l-r小时睡觉次数最多是多少?从0点开始第一次醒来。

比赛的时候没写出来。。。
思路:如果不用dp那么很多就想 我第一次在a[i],a[i]-1的时候睡,然后每次两种情况然后总共2的n次方中复杂度肯定是不够的,但是 h最大也就2000,所以我们可以dp[i][j]表示第i次在j时开始睡
那么 我们要初始化为负无穷大 然后让dp[0][0] = 0;

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 2007;
long long dp[N][N];
long long a[N], n, h, l, r;

int main(){
    scanf("%lld%lld%lld%lld",&n, &h, &l, &r);
    for(int i = 1; i <= n; i++){
        scanf("%lld", &a[i]);
    }
    memset(dp,-0x3f3f3f3f,sizeof(dp));
    dp[0][0] = 0;
    for(int i = 1; i <= n; i++){
        for(int j = 0 ; j <= h ;j++){
            if((j + a[i]) % h >= l && (j + a[i]) % h <= r){
                dp[i][(j + a[i]) % h] = max(dp[i][(j + a[i]) % h], dp[i - 1][j] + 1);
            }else{
                dp[i][(j + a[i]) % h] = max(dp[i][(j + a[i]) % h], dp[i - 1][j]);
            }
            a[i]--;
            if((j + a[i]) % h >= l && (j + a[i]) % h <= r){
                dp[i][(j + a[i]) % h] = max(dp[i][(j + a[i]) % h], dp[i - 1][j] + 1);
            }else{
                dp[i][(j + a[i]) % h] = max(dp[i][(j + a[i]) % h], dp[i - 1][j]);
            }
            a[i]++;
        }
    }
    long long ans = 0;
    for(int i = 0; i < h; i++){
        ans = max (ans, dp[n][i]);
    }
    printf("%lld\n", ans);
}

F. Maximum White Subtree
题意:有一颗树每个节点有颜色 (白,黑),然后让你求以每个节点为根的子树中白-黑最大是多少?

题解 :这题一看就是dp,
我们可以设dp[i]表示以i为根节点然后 向下的连通图中最大值。
然后在dfs一遍求 设 u为父亲节点 v为儿子节点
如果 dp[v] > 0 那么以v
为节点 的向上的联通图中最大值为dp[u] - dp[v];
如果dp[v]<=0 那最大值就是dp[u]
代码:

#include<bits/stdc++.h>
using namespace std;

const int N = 2e5 + 7;
int a[N], dp[N], n , sum[N], up[N], top[N], f[N];
vector<int> g[N];

void dfs(int u, int fa){
    if(a[u] == 1)dp[u] = 1;
    else dp[u] = -1;
    for(int i: g[u]){
        if(i == fa)continue;
        dfs(i, u);
        dp[u] = max(dp[i] + dp[u], dp[u]);
    }
}

void dfs1(int u, int fa){
    for(int i: g[u]){
        if(i == fa){
            continue;
        }
        if(dp[i] > 0 && dp[u] - dp[i] > 0 ) dp[i] += dp[u] - dp[i];
        else if(dp[i] <= 0 && dp[u] > 0) dp[i] += dp[u];
        dfs1(i, u);
    }

}


int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
        if(a[i] == 0)a[i] = -1;
    }
    for(int i = 1; i < n; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, 0);
    dfs1(1, 0);
    for(int i = 1; i <= n; i++){
        printf("%d ", dp[i]);

    }
    puts("");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值