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 <cstring>
#include <vector>
#include <algorithm>

using namespace std;
typedef long long ll;
const int MOD = 1e9+7;
const int maxn = 1e5+5;

int N, v[maxn];
ll dp[maxn][2];
vector<int> g[maxn];

void init () {
    memset(dp, 0, sizeof(dp));

    int x;
    scanf("%d", &N);
    for (int i = 1; i < N; i++) {
        scanf("%d", &x);
        g[x].push_back(i);
    }

    for (int i = 0; i < N; i++)
        scanf("%d", &v[i]);
}

ll pow_mod (ll x, int n, ll mod) {
    ll ret = 1;
    while (n) {
        if (n&1)
            ret = ret * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return ret;
}

ll inv (ll x) {
    if (x == 0)
        return 1;
    return pow_mod(x, MOD-2, MOD);
}

void solve (int u) {
    if (g[u].size() == 0) {
        dp[u][v[u]] = 1;
        return;
    }

    for (int i = 0; i < g[u].size(); i++)
        solve(g[u][i]);

    if (v[u]) {
        dp[u][0] = 0;
        ll& ans = dp[u][1];
        ans = 1;

        for (int i = 0; i < g[u].size(); i++) {
            int k = g[u][i];
            ans = ans * (dp[k][1] + dp[k][0]) % MOD;
        }
    } else {
        dp[u][1] = 0;
        ll& ans = dp[u][0];
        ans = 1;

        for (int i = 0; i < g[u].size(); i++) {
            int k = g[u][i];
            ans = ans * (dp[k][0] + dp[k][1]) % MOD;
        }

        for (int i = 0; i < g[u].size(); i++) {
            int k = g[u][i];
            dp[u][1] += ans * inv(dp[k][0] + dp[k][1]) % MOD * dp[k][1] % MOD;
            dp[u][1] %= MOD;
        }
    }
    //printf("%d %d %d\n", u, dp[u][0], dp[u][1]);
}

int main () {
    init();
    solve(0);
    printf("%lld\n",  dp[0][1] % MOD);
    return 0;
}

版权声明:本文博主原创文章。博客,未经同意不得转载。

时间: 2024-10-07 05:50:07

Codeforces 461B Appleman and Tree(木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 461B. Appleman and Tree[树形DP 方案数]

B. Appleman and Tree time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other vertices are color

CF 461B Appleman and Tree 树形DP

Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other vertices are colored white. Consider a set consisting of k (0 ≤ k < n) edges of Appleman's tree. If Appleman deletes these edges from the tree, then

CodeForces 461B Appleman and Tree:Tree dp

题目链接:http://codeforces.com/problemset/problem/461/B 题意: 给你一棵树(编号从0到n-1,0为根节点),每个节点有黑白两种颜色,其中黑色节点有k+1个. 现在让你删掉k条边,使得这棵树变成k+1个连通块,并且要保证每个连通块中有且仅有一个黑色节点. 问你删边的方案有多少种. 题解: 表示状态: dp[i][0/1] = numbers 表示在节点i所在的连通块中有(1)或没有(0)黑色节点时,节点i的子树的删边方法数 因为总要保证每个连通块中有

【树形DP】CODEFORCES 461B Appleman and Tree

通道 题意:一棵树上有K个黑色节点,剩余节点都为白色,将其划分成K个子树,使得每棵树上都只有1个黑色节点,共有多少种划分方案 思路:dp[i][0]和dp[i][1]分别表示i子树所在联通块不存在黑节点和已经存在一个黑节点的方案数 代码: #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<ma

Codeforces 461B - Appleman and Tree 树状DP

一棵树上有K个黑色节点,剩余节点都为白色,将其划分成K个子树,使得每棵树上都只有1个黑色节点,共有多少种划分方案. 个人感觉这题比较难.假设dp(i,0..1)代表的是以i为根节点的子树种有0..1个黑色节点的划分方案数. 当节点i为白色时,对于它的每个孩子的节点处理: 求dp(i, 0)时有: 1,将该节点与孩子节点相连,但要保证孩子节点所在的子树种没有黑色节点: 2,将该节点不与该孩子节点相连,则该孩子节点要保证所在子树种有黑色节点: 即dp(i, 0) = π(dp(j,0 ) + dp(

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 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

codeforces 461B Appleman and Tree

题意:问你将含有黑白点的无向树使得每个子树中只有一个黑点的方法数. 解题思路:树形dp,dp[i][0/1] 表示 第i 个节点的联通图中是否有 1个黑点的种类数. 解题代码: 1 // File Name: 461c.cpp 2 // Author: darkdream 3 // Created Time: 2015年03月11日 星期三 10时53分22秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8