1 条题解
-
0
自动搬运
来自洛谷,原作者为

teylnol_evteyl
我是狸猫盘的猫 | 哇,Teylnol Evteyl! | 很慢地摇头搬运于
2025-08-24 22:49:56,当前版本为作者最后更新于2023-08-21 11:25:01,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
设 表示节点 的颜色, 表示只考虑原树中 的子树中的点、选择点 的方案数。对于儿子 ,可以选择同色儿子节点,也可以跳过这个儿子节点,选择 的与 同色的儿子节点 ,故状态转移方程为:
$$f_u=\prod[c_u=c_v]f_v+\left(\prod[c_u=c_w]f_w+1\right) $$其中 是 的儿子, 是 的儿子。
统计答案时,除了考虑选择的点的最近公共祖先被选择的情况(即 ),还有最近公共祖先没有被选择的情况,也就是说一个节点 的几个儿子节点颜色相同,则可以分别在它们的子树中选择,而不选 。设 表示考虑 的子树,不选择 ,选择至少两个颜色为 的儿子节点的方案数,因为要分别减去选择 或 个儿子的情况,所以:
$$g_{u,c}=\left(\prod[c_v=c]f_v+1\right)-\left(\sum[c_v=c]f_v\right)-1 $$其中 是 的儿子。
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 1e5 + 5, P = 1e9 + 7; int n, c[N]; int la[N], ne[N * 2], en[N * 2], idx; LL f[N], g[N], res; void add(int a, int b) { ne[ ++ idx] = la[a]; la[a] = idx; en[idx] = b; } void dp(int u, int fa) { f[u] = 1; for(int i = la[u]; i; i = ne[i]) { int v = en[i]; if(v == fa) continue ; dp(v, u); LL t = 1; for(int j = la[v]; j; j = ne[j]) { int w = en[j]; if(w == u) continue ; if(c[w] == c[u]) t = t * (f[w] + 1) % P; } if(c[v] == c[u]) t = (t + f[v]) % P; f[u] = f[u] * t % P; } for(int i = la[u]; i; i = ne[i]) { int v = en[i]; if(v == fa) continue ; g[c[v]] = g[c[v]] * (f[v] + 1) % P; } for(int i = la[u]; i; i = ne[i]) { int v = en[i]; if(v == fa) continue ; res = (res + g[c[v]] - 1) % P; g[c[v]] = 1; } } int main() { scanf("%d", &n); for(int i = 1; i <= n; i ++ ) scanf("%d", &c[i]); for(int i = 1; i < n; i ++ ) { int a, b; scanf("%d%d", &a, &b); add(a, b), add(b, a); } add(0, 1); for(int i = 1; i <= n; i ++ ) g[i] = 1; dp(0, 0); printf("%lld\n", res); return 0; }
- 1
信息
- ID
- 9052
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者