Codeforces 633F The Chocolate Spree 树形dp

The Chocolate Spree

对拍拍了半天才知道哪里写错了。。

dp[ i ][ j ][ k ]表示在 i 这棵子树中有 j 条链, 是否有链延伸上来。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ull unsigned long long

using namespace std;

const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-6;
const double PI = acos(-1);

int n, a[N];
LL dp[N][3][2];

vector<int> G[N];

inline bool chkmax(LL &a, LL b) {
    return a < b ? a = b, true : false;
}

void dfs(int u, int fa) {
    LL tmp[5][3];
    LL gg[5][3];
    dp[u][0][0] = 0;
    for(int i = 0; i < 5; i++)
        for(int j = 0; j < 3; j++)
            tmp[i][j] = -INF;
    tmp[0][0] = 0;
    for(auto& v : G[u]) {
        if(v == fa) continue;
        dfs(v, u);
        memcpy(gg, tmp, sizeof(gg));
        for(int i = 0; i <= 2; i++) {
            for(int j = 0; j <= 2; j++) {
                for(int x = 0; x <= 2; x++) {
                    for(int y = 0; y <= 1; y++) {
                        if(!i && j || !x && y) continue;
                        if(j + y > 2) continue;
                        tmp[i + x][j + y] = max(tmp[i + x][j + y], gg[i][j] + dp[v][x][y]);
                    }
                }
            }
        }
    }
    // dp[1][0]
    chkmax(dp[u][1][0], tmp[0][0] + a[u]);
    chkmax(dp[u][1][0], tmp[1][0]);
    chkmax(dp[u][1][0], tmp[1][1] + a[u]);
    chkmax(dp[u][1][0], tmp[2][2] + a[u]);

    // dp[1][1]
    chkmax(dp[u][1][1], tmp[0][0] + a[u]);
    chkmax(dp[u][1][1], tmp[1][1] + a[u]);

    //dp[2][0]
    chkmax(dp[u][2][0], tmp[2][0]);
    chkmax(dp[u][2][0], tmp[2][1] + a[u]);
    chkmax(dp[u][2][0], tmp[3][2] + a[u]);

    //dp[2][1]
    chkmax(dp[u][2][1], tmp[2][1] + a[u]);
    chkmax(dp[u][2][1], tmp[2][2] + a[u]);
    chkmax(dp[u][2][1], tmp[1][0] + a[u]);
}

int main() {
//    freopen("test.in", "r", stdin);
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) G[i].clear();
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    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);
    }
    for(int i = 1; i <= n; i++)
        for(int j = 0; j < 3; j++)
            for(int k = 0; k < 2; k++)
                dp[i][j][k] = -INF;
    dfs(1, 0);
    LL ans = 0;
    for(int i = 0; i <= 2; i++)
        for(int j = 0; j <= 1; j++)
            ans = max(ans, dp[1][i][j]);
    printf("%lld\n", ans);
    return 0;
}

/*
*/

原文地址:https://www.cnblogs.com/CJLHY/p/10641758.html

时间: 2024-10-10 06:26:26

Codeforces 633F The Chocolate Spree 树形dp的相关文章

Codeforces 461B Appleman and Tree(树形dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每个节点的父亲节点,以及每个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量,保证每个联通分量有且仅有1个黑色节点.问有多少种分割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的分割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include <c

Codeforces 462D Appleman and Tree 树形dp

题目链接:点击打开链接 题意: 给定n个点的树, 0为根,下面n-1行表示每个点的父节点 最后一行n个数 表示每个点的颜色,0为白色,1为黑色. 把树分成若干个联通块使得每个联通块有且仅有一个黑点,问有多少种分法(结果mod1e9+7) 思路: 树形dp,每个点有2个状态,已经归属于某个黑点和未归属于某个黑点. #include <cstdio> #include <vector> #include <iostream> using namespace std; #de

Codeforces 543D Road Improvement(树形DP+乘法逆元)

题目大概说给一棵树,树的边一开始都是损坏的,要修复一些边,修复完后要满足各个点到根的路径上最多只有一条坏的边,现在以各个点为根分别求出修复边的方案数,其结果模1000000007. 不难联想到这题和HDU2196是一种类型的树形DP,因为它们都要分别求各个点的答案.然后解法也不难想: dp0[u]表示只考虑以u结点为根的子树的方案数 dp1[u]表示u结点往上走,倒过来,以它父亲为根那部分的方案数 有了这两部分的结果,对于各个点u的答案就是dp0[u]*(dp1[u]+1).这两部分求法如下,画

Codeforces 627D Preorder Test(二分+树形DP)

题意:给出一棵无根树,每个节点有一个权值,现在要让dfs序的前k个结点的最小值最大,求出这个值. 考虑二分答案,把>=答案的点标记为1,<答案的点标记为0,现在的任务时使得dfs序的前k个节点都为1. 考虑树形DP. 用dp[u]表示从节点u开始在子树中进行dfs最多可以经过多少个为1的结点,显然,若某一个子树中节点全为1,那么这个可以加到dp[u]中,此外还可以在不全为1的子树中挑选一个加到dp[u]上. 那么答案就是从标记为1的节点当做根,选两颗不完全子树和所有的完全子树(包括从父亲向上的

Codeforces 919D Substring (拓扑排序+树形dp)

题目:Substring 题意:给你一个有向图, 一共有n个节点 , m条变, 一条路上的价值为这个路上出现过的某个字符最多出现次数, 现求这个最大价值, 如果价值可以无限大就输出-1. 题解:当这个有向图构成一个环的时候就会使得值无限大,所以先用拓扑排序判断一下有没有环,如果有环直接输出-1, 如果没有环就再使用树形dp并记忆化存数,来找到最大值. 代码: 1 #include<cstring> 2 #include<iostream> 3 using namespace std

codeforces 598E E. Chocolate Bar(区间dp)

题目链接: E. Chocolate Bar time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output You have a rectangular chocolate bar consisting of n × m single squares. You want to eat exactly k squares, so you ma

CodeForces 55D Beautiful numbers (树形DP)

想了半天,总算想出来了.这题刚上来的思路很明显是11维DP..但是明显不可取.. 这题的关键在于只要两个数前面的拥有的数字是一样的,而且此时与其最小公倍数的模是一样的,那么这时候就可以认为对所有的数字取模都是相等的,那么后面的总情况数属于完美数的情况也是相同的. 只要想到这步的话,那么基本思路就出来了,我第一次居然脑残的记录lcm与模2520(2到9的最小公倍数),首先lcm相同并不代表出现的数字相同先不说,仅仅这个最大值就太大了,lcm最大是2520,这样的话就需要开一个20*2520*252

Codeforces 700B Connecting Universities(树形DP)

[题目链接] http://codeforces.com/problemset/problem/700/B [题目大意] 给出 一棵n个节点的树, 现在在这棵树上选取2*k个点,两两配对,使得其配对的两点间距离的和最大. [题解] 求出树的加权重心,那么答案就是每个点到加权重心的距离之和,但是实际上,并不需要求出加权重心,观察树边和其两边的询问节点,可以发现一个优美的性质,每条边对答案的贡献值为min(左边的点数,右边的点数),因此,树规计算每条边的贡献值,累加和就是答案. [代码] #incl

codeforces 416B. Appleman and Tree 树形dp

题目链接 Fill a DP table such as the following bottom-up: DP[v][0] = the number of ways that the subtree rooted at vertex v has no black vertex. DP[v][1] = the number of ways that the subtree rooted at vertex v has one black vertex. The recursion pseudo