题意:给定一棵树,初始状态下所有树的节点都是红色,现在按照下述程序递归对树进行染色,问所有染色的方法数.
染色方法:
int p()
{}//等可能地返回0和1
int count;//全局变量,初始值为0.
void paint(s)
{
int v = p();
if(v == 0) 将点s染为白色.
else 将点s染为黑色.
v = p();
if(v == 0) 将s的孩子按序号从大到小放在数组a[]中.
else 将s的孩子按序号从小到大放在数组a[]中.
for(s的每一个孩子)
{
if(p()) paint(v);
}
}
解法:首先注意到,对于以点u为根的一棵子树,将点u染成白色和黑色的方法都一一对应.所以对于点u,有意义的状态是:dp[u][0]:以u为根的子树中包含点u共染了偶数个点,dp[u][1]:以u为根的子树中包含点u共染了奇数个点.最后的答案就是dp[1][0]+dp[1][1].
先考虑从左往右染色,则到u的一个孩子v时有以下转移方程:(注意奇偶相互对应)
ll add_dp0 = dp[u][0] * dp[v][0] % MOD + dp[u][1] * dp[v][1] % MOD;
ll add_dp1 = dp[u][1] * dp[v][0] % MOD + dp[u][0] * dp[v][1] % MOD;
dp[u][0] = (dp[u][0] + add_dp0) % MOD;//选或者不选
dp[u][1] = (dp[u][1] + add_dp1) % MOD;
从左往右和从右往左是相互对应的过程,所以对dp[u][0]和dp[u][1]都乘以2.
重复计数的部分:奇数个染了奇数个的子树的方法数和全部都是染了偶数个的子树,再次dp处理即可.
转移方程:
int v = g[u][i];
ll val = dp2[0][0];
dp2[0][0] = (dp2[0][0] + dp[v][0] * dp2[0][1]) % MOD;
dp2[0][1] = (dp2[0][1] + dp[v][0] * val) % MOD;
val = dp2[1][0];
dp2[1][0] = (dp2[1][0] + dp[v][1] * dp2[1][1]) % MOD;
dp2[1][1] = (dp2[1][1] + dp[v][1] * val) % MOD;
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <iostream>
#include <iomanip>
using namespace std;
typedef long long ll;
const int MAXN = 100005;
const int MOD = 1000000007;
vector<int> g[MAXN];
int n;
ll dp[MAXN][2];
ll dp2[2][2];
void dfs(int u)
{
dp[u][0] = 0, dp[u][1] = 1;
int size = (int)g[u].size();
if (size == 0) return;
for (int i = 0; i < size; ++ i) dfs(g[u][i]);
for (int i = 0; i < size; ++ i) {
int v = g[u][i];
ll add_dp0 = dp[u][0] * dp[v][0] % MOD + dp[u][1] * dp[v][1] % MOD;
ll add_dp1 = dp[u][1] * dp[v][0] % MOD + dp[u][0] * dp[v][1] % MOD;
dp[u][0] = (dp[u][0] + add_dp0) % MOD;
dp[u][1] = (dp[u][1] + add_dp1) % MOD;
}
dp[u][0] = (dp[u][0] + dp[u][0]) % MOD;
dp[u][1] = (dp[u][1] + dp[u][1]) % MOD;
dp2[0][0] = dp2[1][0] = 1;
dp2[0][1] = dp2[1][1] = 0;
for (int i = 0; i < size; ++ i) {
int v = g[u][i];
ll val = dp2[0][0];
dp2[0][0] = (dp2[0][0] + dp[v][0] * dp2[0][1]) % MOD;
dp2[0][1] = (dp2[0][1] + dp[v][0] * val) % MOD;
val = dp2[1][0];
dp2[1][0] = (dp2[1][0] + dp[v][1] * dp2[1][1]) % MOD;
dp2[1][1] = (dp2[1][1] + dp[v][1] * val) % MOD;
}
dp[u][0] = (dp[u][0] + MOD - dp2[1][1]) % MOD;
dp[u][1] = (dp[u][1] + MOD - dp2[0][0] + MOD - dp2[0][1]) % MOD;
}
int MAIN()
{
cin >> n;
int p;
for (int i = 2; i <= n; ++ i) {
cin >> p;
g[p].push_back(i);
}
dfs(1);
cout << (dp[1][0] + dp[1][1]) % MOD << endl;
return 0;
}
int main()
{
ios::sync_with_stdio(false);
cout << fixed << setprecision(16);
return MAIN();
}