QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#708704#9530. A Game On TreeGrenierWA 1ms7712kbC++203.0kb2024-11-04 04:08:362024-11-04 04:08:37

Judging History

This is the latest submission verdict.

  • [2024-11-04 04:08:37]
  • Judged
  • Verdict: WA
  • Time: 1ms
  • Memory: 7712kb
  • [2024-11-04 04:08:36]
  • Submitted

answer

// 很巧妙的题目
// 首先根据期望的贡献公式把贡献分成两个部分(自己的贡献和两两相互的贡献)
// (平方的期望一般都这么处理,不然就只能按照定义枚举E(x^2)的x进行计算,这显然是无法做到的)
// 然后第一部分直接可以统计
// 第二部分其实是一个路径问题,而且是一个与树的结构无关的统计!
// 想到了什么!
// 显然可以转化成点分治的思考方式来解决。不过这里由于统计的性质比较简单,所以并不用真的去用点分治重新建树计算,直接简单的换根dp就可以了
// 由于这里是边的最近公共祖先,所以和点的讨论稍微有些区别

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <unordered_map>
#include <cstring>
#include <set>

#define int long long
typedef long long ll;
typedef double db;
typedef std::pair<int, int> PII;

const int mod = 998244353;
const int N = 1e5, M = 1e5;
int head[N + 2], nxt[M * 2 + 2], ver[M * 2 + 2], edge[M * 2 + 2], tot;
int n, sz[N + 2], res1, res2, sm[N + 2];

int q_pow(int x, int y) {
	if (!y) return 1;
	int mid = q_pow(x, y / 2);
	if (y % 2) return mid * mid % mod * x % mod;
	else return mid * mid % mod;
}

void add(int x, int y, int z = 0) {
	tot++;
	edge[tot] = z;
	ver[tot] = y;
	nxt[tot] = head[x];
	head[x] = tot;
}

void dfs(int x, int fa) {
	sz[x] = 1;
	int res = 0;
	for (int i = head[x]; i; i = nxt[i]) {
		int y = ver[i];
		if (y == fa) continue;
		dfs(y, x);
		sz[x] += sz[y];
		(sm[x] += sm[y]) %= mod;
		(res += sm[y] * sm[y] % mod) %= mod;
	}
	// 这里是一个数学优化,处理两个边不在同一个子树内的情况,自带2倍???是否要除2
	(res2 += sm[x] * sm[x]) %= mod;
	(res2 += mod - res) %= mod;
	for (int i = head[x]; i; i = nxt[i]) {
		int y = ver[i];
		if (y == fa) continue;
		res2 += 2LL * q_pow((n - sz[y]), 2) % mod * q_pow((sm[y] - sz[y] + mod) % mod, 2) % mod;
		res2 %= mod;
	}

	(sm[x] += sz[x]) %= mod; // 统计子树的sz和
	res1 += sz[x] * sz[x] % mod * (n - sz[x]) % mod * (n - sz[x]) % mod;
	res1 %= mod;
	// std::cout << x << " " << res1 << " " << res2 << std::endl;
}

inline int inv(int x) {
	return q_pow(x, mod - 2);
}

void solve() {
	std::cin >> n; tot = res1 = res2 = 0;
	for (int i = 1; i <= n; i++) head[i] = 0;
	for (int i = 1; i < n; i++) {
		int a, b;
		std::cin >> a >> b;
		add(a, b), add(b, a);
	}
	dfs(1, 0);
	// for (int i = 1; i <= n; i++) {
	// 	std::cout << sm[i] << std::endl;
	// }
	// std::cout << res1 << " " << res2 << std::endl;
	int ans = (res1 + res2) % mod;
	// std::cout << ans * n % mod * (n - 1) % mod << std::endl;
	int frac = n % mod * (n - 1) % mod * inv(2) % mod;
	std::cout << (ans * inv(frac) % mod) << std::endl;
}

signed main() {
	std::ios::sync_with_stdio(0);
	std::cin.tie(0), std::cout.tie(0);
	int times = 1;
	std::cin >> times;
	while (times--) {
		solve();
	}
	return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 0
Wrong Answer
time: 1ms
memory: 7712kb

input:

2
3
1 2
2 3
5
1 2
1 5
3 2
4 2

output:

332748121
61

result:

wrong answer 1st lines differ - expected: '443664158', found: '332748121'