CF1777D Score of a Tree 题解

题目简述

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

在每一个 t>0 时,每个结点的值都会变成其子结点在 t1 时的值的异或和。

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

定义 F(A) 为树在 0t10100 中所有 S(t) 的和。其中 A 为树在时刻 0 时每个结点的值。

求所有 2nF(A) 的和。

思路

引理

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

归纳证明:

t=0 时成立。

假设在 t=k 时成立。

则在 t=k+1 时:

1.如果结点 i 的任意一子结点 u,du>k

di=max{du}+1

di>k+1

2.如果结点 i 的子结点在 t=k 时有 j 个结点有 duk

所以一共有 2j 种选取方法。异或和为 1 的方案数为 Cj1+Cj3+Cj5+

Cj1+Cj3+Cj5+

=Cj10+Cj11+Cj12+Cj13+Cj14+Cj15++Cj1j1(若 j 为奇数, Cj1j=0 )

=2j1

=2j×50%

此时结点 i1 的概率为 50%

证毕

由于 din2×10510100

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

根据引理,每个结点对答案的贡献即为 2n1×(di+1)

所以用 DFS 来求 di 即可。

代码

#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 @   [/]码农1号[/]  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示