题目简述
给你一个 \(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 << ' ';
}
}
标签:tmp,结点,le,int,题解,Tree,long,Score,ans
From: https://www.cnblogs.com/easonhe/p/17397414.html