您的位置:首页 > 其它

CF - 461B 树形dp

2016-11-09 19:36 351 查看

题意:

给出一棵n个节点的无根树,每个节点要么是0,要么是1,现在要把树分成若干区域,要求每个节点都必须属于一个区域,而且一个区域中只能有一个节点为1。问一共有多少种分法?

思路:

设dp[i][0]表示节点i属于某个没有1的区域的方案数,dp[i][1]表示节点i属于某个有1的区域的方案数。可以得到状态转移方程:

dp[u][0] = dp[u][0] * (dp[v][0] + dp[v][1]);

dp[u][1] = dp[u][1] * (dp[v][0] + dp[v][1]) + dp[u][0] * dp[v][1];

自下而上dfs进行一遍dp即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 10;
const ll MOD = 1e9 + 7;

vector <int> tree[MAXN];
ll dp[MAXN][2];
int a[MAXN];

void dfs(int u, int pre) {
dp[u][1] = a[u];
dp[u][0] = a[u] ^ 1;
int cnt = tree[u].size();
for (int i = 0; i < cnt; i++) {
int v = tree[u][i];
if (v == pre) continue;
dfs(v, u);
ll old[2] = {dp[u][0], dp[u][1]};
dp[u][0] = (old[0] * dp[v][0] % MOD + old[0] * dp[v][1] % MOD) % MOD;
dp[u][1] = (old[1] * dp[v][0] % MOD + old[1] * dp[v][1] % MOD + old[0] * dp[v][1] % MOD) % MOD;
}
}

int main() {
//freopen("in.txt", "r", stdin);
int n, x;
scanf("%d", &n);
for (int i = 1; i < n; i++) {
scanf("%d", &x);
tree[i].push_back(x);
tree[x].push_back(i);
}
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
dfs(0, -1);
printf("%I64d\n", dp[0][1]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: