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]); }
相关文章推荐
- 【CF739B】Alyona and a tree(树上差分,二分,树形DP)
- CF 294E - Shaass the Great 树形dp
- CF 219 D:Choosing Capital for Treeland(树形dp)
- CF 219D Choosing Capital for Treeland (树形dp)
- CF 533 B. Work Group 树形dp
- CF 161D Distance in Tree 树形DP(套路,路径长度为k点对)
- codeforces 461B B. Appleman and Tree(树形dp)
- 树形dp-CF-337D. Book of Evil
- cf 682 C (树形dp)
- CF 581F Contest Page 树形DP
- 树形DP入门题 cf 161D
- CF 461B Appleman and Tree 树形dp
- CF 219D Choosing Capital for Treeland 【树形dp + 思维】
- CF round 277 (div2) D题 树形dp
- cf 135div2D Choosing Capital for Treeland 【树形dp】
- CF_D. Choosing Capital for Treeland_树形DP
- CF 708C. Centroids 树形dp
- CF 463A && 463B 贪心 && 463C 霍夫曼树 && 463D 树形dp && 463E 线段树
- CF 161D Distance in Tree 树形DP
- CF618D:Hamiltonian Spanning Tree(贪心 & 树形dp & 最小路径覆盖)