题目描述
把树上一些染成黑色,满足任意两个黑色点的 lca 也被染成黑色了。
求染色方案数对 取模。
正解
考虑 dfs 的过程中:
一个点的两个不同的子树内有节点被染色,这个节点就必须被染色。
否则这个点它可以任意选择染色或者不染色。
那么很容易设出状态 表示一个点的子树内(包括自己)是否有节点染色的方案数。
根据上面两个描述很容易得到下面的转移方程:
只有一颗子树内染了色的方案数(当前节点选 0) +
(当前节点选 1)
时间复杂度 。
代码
#include <bits/stdc++.h>
#define N 1000005
using namespace std;
const int mod = 1e9 + 7;
int n;
int head[N], nex[N << 1], to[N << 1], ecnt;
int f[N][2];
inline void addE(int u, int v) {
to[++ecnt] = v;
nex[ecnt] = head[u], head[u] = ecnt;
}
inline int fpm(int x, int y) {
int r = 1;
while(y) {
if(y & 1) r = 1LL * x * r % mod;
x = 1LL * x * x % mod, y >>= 1;
}
return r;
}
void dfs(int u, int fa) {
int r1 = 1, r2 = 1, r3 = 0;
for(int i = head[u], v; i; i = nex[i]) {
v = to[i];
if(v == fa) continue;
dfs(v, u);
r1 = 1LL * r1 * (f[v][0] + f[v][1]) % mod;
r2 = 1LL * r2 * f[v][0] % mod;
}
for(int i = head[u], v; i; i = nex[i]) {
v = to[i];
if(v == fa) continue;
r3 = (r3 + 1LL * r2 * fpm(f[v][0], mod - 2) % mod * f[v][1]) % mod;
}
f[u][0] = r2;
f[u][1] = (r1 + r3) % mod;
}
inline int read() {
int x = 0; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
return x;
}
int main() {
n = read();
for(int i = 1, u, v; i < n; ++i) {
u = read(), v = read();
addE(u, v), addE(v, u);
}
dfs(1, 0);
int ans = (f[1][0] + f[1][1]) % mod;
printf("%d\n", ans);
return 0;
} 
京公网安备 11010502036488号