CF1777D Score of a Tree 题解

题目简述

给你一个 \(n\) 个结点根为 \(1\) 的树。在 \(t = 0\) 时,每个结点都有一个值,为 \(0\)\(1\)

在每一个 \(t > 0\) 时,每个结点的值都会变成其子结点在 \(t - 1\) 时的值的异或和。

定义 \(S(t)\)\(t\) 时所有结点值的和。

定义 \(F(A)\) 为树在 \(0 \le t \le 10^{100}\) 中所有 \(S(t)\) 的和。其中 \(A\) 为树在时刻 \(0\) 时每个结点的值。

求所有 \(2^n\)\(F(A)\) 的和。

思路

引理

引理:设 \(d_i\) 为第 \(i\) 个结点与其子树中结点距离的最大值。如果 \(d_i > t\) 则该结点在 \(t\) 时刻的值为 \(0\) 。如果 \(d_i \le t\) 则该结点在 \(t\) 时刻是 \(1\) 的几率为 \(50\%\)

归纳证明:

\(t = 0\) 时成立。

假设在 \(t = k\) 时成立。

则在 \(t = k + 1\) 时:

1.如果结点 \(i\) 的任意一子结点 \(u, d_u > k\)

\(\because d_i = \max\{d_u\}+1\)

\(\therefore d_i > k + 1\)

2.如果结点 \(i\) 的子结点在 \(t = k\) 时有 \(j\) 个结点有 \(d_u \le k\)

所以一共有 \(2^j\) 种选取方法。异或和为 \(1\) 的方案数为 \(C_j^1 + C_j^3 + C_j^5 + \cdots\)

\(\because C_j^1 + C_j^3 + C_j^5 + \cdots\)

\(= C_{j-1}^0+C_{j-1}^1+C_{j-1}^2+C_{j-1}^3+C_{j-1}^4+C_{j-1}^5+\cdots+C_{j-1}^{j-1}\)(若 \(j\) 为奇数, \(C_{j-1}^j=0\) )

\(=2^{j-1}\)

\(=2^j\times50\%\)

\(\therefore\) 此时结点 \(i\)\(1\) 的概率为 \(50\%\)

证毕

由于 \(d_i \leq n \leq 2\times 10^5 \leq10^{100}\)

由于 \(t\) 值很大,所以最后所有结点的值均为 \(0\)

根据引理,每个结点对答案的贡献即为 \(2 ^ {n - 1} \times (d_i + 1)\)

所以用 DFS 来求 \(d_i\) 即可。

代码

#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
const int N = 2E5 + 5, M = 1E9 + 7;
int n, t;
int u, v;
long long tmp = 0; 
vector<int> G[N];
long long dfs(int u, int f) {
	long long ans = 1;
	for (int v : G[u]) {
		if (v == f) continue;
		ans = max(ans, dfs(v, u) + 1);
	}
	tmp += ans;
	tmp %= M;
	return ans;
}
int main()
{
	cin >> t;
	while (t--) {
		cin >> n;
		for (int i = 1; i <= n; i++) G[i].clear();
		for (int i = 1; i < n; i++) {
			cin >> u >> v;
			G[u].push_back(v);
			G[v].push_back(u);
		}
		long long ans = 1;
		for (int i = 1; i < n; i++) {
			ans *= 2;
			ans %= M;
		}
		tmp = 0;
		dfs(1, 0);
		ans = ans * tmp;
		ans %= M;
		cout << ans << ' ';
	}
}
posted @ 2023-05-13 14:58  [/]码农1号[/]  阅读(38)  评论(0)    收藏  举报