codeforces 461B 树DP

来源:互联网 发布:音频美化软件 编辑:程序博客网 时间:2024/05/29 19:15

题意:给出一棵树,每个节点的颜色为黑色或者白色,现在可以切割任意条边,使得答案这个树被分成若干块,每块至多一个黑色点。问方案数有多少。

对于树dp,一般用dp[u]表示当前u节点的子树的方案数,然后根据其与子节点的关系进行转移。
对于这题我们还需要记录,当前子树中是否已经有黑色点了,如果有,就可以切割,没有,就不能切割。这样状态的构造和转移都已经出来了。
dp[u][0/1],代表当前u节点的子树中,是否有黑色节点。
dp[u][1]=dp[u][1]dp[v][0]()+dp[u][1]dp[v][1]()+dp[u][0]dp[v][1]()
dp[u][0]=dp[u][0]dp[v][0]()+dp[u][0]dp[v][1]()

需要注意dp[u][1]的转移中用到的是与当前的v讨论关系之前的dp[u][0],因此转移的顺序需要注意下。

#include <bits/stdc++.h>using namespace std;typedef long long LL;const LL mod = 1e9+7;const LL maxn = 110000;namespace treedp {    LL n;    vector<LL> G[maxn];    LL dp[maxn][2];    void dfs(LL u, LL fa) {        for(LL i = 0; i < G[u].size(); i++) {            LL v = G[u][i];            if(v == fa) continue;            dfs(v, u);            dp[u][1] = (dp[u][1] * (dp[v][0] + dp[v][1]) % mod + dp[u][0] * dp[v][1]) % mod;            dp[u][0] = (dp[u][0] * (dp[v][0] + dp[v][1])) % mod;        }    }    void solve() {        scanf("%d", &n);        for(LL i = 1; i < n; i++) {            LL p;            scanf("%lld", &p);            G[p].push_back(i);            G[i].push_back(p);        }        for(LL i = 0; i < n; i++) {            LL v;            scanf("%lld", &v);            dp[i][v] = 1;        }        dfs(0, -1);        printf("%d\n", dp[0][1]);    }}int main() {    treedp::solve();    return 0;}
原创粉丝点击