首页 > 其他分享 >AtCoder Grand Contest 058 F Authentic Tree DP

AtCoder Grand Contest 058 F Authentic Tree DP

时间:2023-09-14 20:11:05浏览次数:57  
标签:AtCoder typedef frac Contest Tree long 边点 maxn

洛谷传送门

AtCoder 传送门

人生中第一道 AtCoder 问号题。

设 \(P = 998244353\)。

注意到 \(f(T)\) 的定义式中,\(\frac{1}{n}\) 大概是启示我们转成概率去做。发现若把 \(\frac{1}{n}\) 换成 \(\frac{1}{n - 1}\) 答案就是 \(1\),所以 \(\frac{1}{n}\) 大概是要转成点数之类的。

考虑把边转成点,若原树存在边 \((u, v)\),就新建点 \(p\),断开 \((u, v)\),连边 \((u, p), (p, v)\),称 \(p\) 点为边点。但是这样点数就变成 \(2n - 1\) 了。

但是!考虑再挂 \(P - 1\) 个叶子到 \(p\) 下面,点数就变成 \(n + (n - 1) \times P\)。模意义下 \(\frac{1}{n} \equiv \frac{1}{n + (n - 1)P} \pmod P\)。

我们可以把原问题转化成在新树上的这个问题:

随机生成一个排列 \(p_{1 \sim n + (n - 1)P}\),求所有边点的 \(p\) 值大于其所有邻居的 \(p\) 值的概率。

证明大概就是考虑不断取树上的最大值,取 \(n - 1\) 次,每次取边点的概率在模意义下等于 \(\frac{1}{n}\),转移式也与原题相同。

考虑给树上的边定向,从小连到大,那么就是要求每条边的起点都是边点的概率。像这样(图来自 kkio):

随便定一个根。发现有些 \(p \to u\) 的边从下连到上看起来不顺眼,考虑容斥。那么所有下连到上的边可以选择上连到下或者下连到上(断掉)。设有 \(k\) 条原本是下连到上的边,容斥系数为 \((-1)^k\)。

那么我们可以设 \(f_{u, i}\) 表示,\(u\) 的子树中以 \(u\) 为根的外向树大小模 \(P\) 意义下等于 \(i\),容斥系数乘概率之和。

对于一个边点 \(p\),在它原树上对应的边 \((u, v)\) 上统计贡献。

考虑若边 \((u, p)\) 从上到下,那 \(v\) 子树中以 \(v\) 为根的的外向树可以直接接到 \(u\) 下面,\(p\) 直接树形背包合并,\(f_{u, i + j} \gets -f'_{u, i} \times \frac{f_{v, j}}{j}\)。乘 \(\frac{1}{j}\) 是计入边点作为外向树的根的概率,乘 \(-1\) 是计入容斥系数。若边 \((u, p)\) 断开,那么 \(f_{u, i} \gets f'_{u, i} \times \sum\limits_{j = 1}^{sz_v} \frac{f_{v, j}}{j}\)。最后还要 \(f_{u, i} \gets \frac{f_{u, i}}{i}\),表示 \(u\) 点作为外向树的根的概率。

时间复杂度 \(O(n^2)\)。

code
// Problem: F - Authentic Tree DP
// Contest: AtCoder - AtCoder Grand Contest 058
// URL: https://atcoder.jp/contests/agc058/tasks/agc058_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 5050;
const ll mod = 998244353;

ll n, f[maxn][maxn], g[maxn], h[maxn], inv[maxn], sz[maxn];
vector<int> G[maxn];

void dfs(int u, int fa) {
	sz[u] = 1;
	f[u][1] = 1;
	for (int v : G[u]) {
		if (v == fa) {
			continue;
		}
		dfs(v, u);
		for (int i = 1; i <= sz[u] + sz[v]; ++i) {
			h[i] = f[u][i];
			f[u][i] = 0;
		}
		for (int i = 1; i <= sz[u]; ++i) {
			for (int j = 1; j <= sz[v]; ++j) {
				f[u][i + j] = (f[u][i + j] - h[i] * f[v][j] % mod * inv[j] % mod + mod) % mod;
			}
		}
		for (int i = 1; i <= sz[u]; ++i) {
			f[u][i] = (f[u][i] + h[i] * g[v] % mod) % mod;
		}
		sz[u] += sz[v];
	}
	for (int i = 1; i <= sz[u]; ++i) {
		f[u][i] = f[u][i] * inv[i] % mod;
		g[u] = (g[u] + f[u][i] * inv[i] % mod) % mod;
	}
}

void solve() {
	scanf("%lld", &n);
	inv[1] = 1;
	for (int i = 2; i <= n; ++i) {
		inv[i] = (mod - mod / i) * inv[mod % i] % mod;
	}
	for (int i = 1, u, v; i < n; ++i) {
		scanf("%d%d", &u, &v);
		G[u].pb(v);
		G[v].pb(u);
	}
	dfs(1, -1);
	ll ans = 0;
	for (int i = 1; i <= n; ++i) {
		ans = (ans + f[1][i]) % mod;
	}
	printf("%lld\n", ans);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:AtCoder,typedef,frac,Contest,Tree,long,边点,maxn
From: https://www.cnblogs.com/zltzlt-blog/p/17703336.html

相关文章

  • The 2021 ICPC Asia Macau Regional Contest
    目录写在前面AKFCGI写在最后写在前面比赛地址:https://codeforces.com/gym/104373当了一场口胡选手。我是彩笔。以下按个人向难度排序。A随便找条路径,检查路径是否满足条件,满足则直接输出,否则倒序输出。CodebyYRMrSu:#include<bits/stdc++.h>#defineLLlonglongusing......
  • AGC058 F Authentic Tree DP
    一道问号题,AT赛场上没人通过。其实是联考题这道题十分有意思,做法很简单但是要想到是极其困难的。考场上我也拿着推了很久猜测这个式子的组合意义,擦到了正解的一些边。然而正解的思想还是太反直觉了。首先题目中的式子实际上是让我们对树上的边建一颗笛卡尔树,然后计算笛卡尔树所......
  • AtCoder Beginner Contest 319 全部题解
    AtCoderBeginnerContest319全部题解ALegendaryPlayers该题只需使用判断来写出所有的答案,注意不要复制错。#include<bits/stdc++.h>usingnamespacestd;strings;intmain(){ cin>>s; if(s=="tourist")cout<<3858<<endl; if(s=="ksun4......
  • TreeView的基本使用,以及和TableView的区别
    Qt中的QTreeView是一个用于显示树形数据的强大控件,通常用于显示层次结构数据。以下是使用QTreeView的基本步骤:创建一个QTreeView实例:在你的主窗口或其他窗口部件中创建一个QTreeView实例:QTreeView*treeView=newQTreeView(this);创建一个数据模型:QTreeView需要一个数......
  • 1135 Is It A Red-Black Tree
    题目:Thereisakindofbalancedbinarysearchtreenamed red-blacktree inthedatastructure.Ithasthefollowing5properties:(1)Everynodeiseitherredorblack.(2)Therootisblack.(3)Everyleaf(NULL)isblack.(4)Ifanodeisred,thenbot......
  • Java树形菜单_轻量级js树形插件_jsTree树形插件
    //插件效果//代码<!DOCTYPEhtml><html><head><title>JS轻量级树形插件</title><metacharset="utf-8"><linkrel="stylesheet"href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/def......
  • 界面控件DevExpress WPF TreeMap,轻松可视化复杂的分层结构数据!
    DevExpressWPF TreeMap控件允许用户使用嵌套的矩形块可视化复杂的平面或分层结构数据。P.S:DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的......
  • 平衡二叉树(Balanced Binary Tree)
    平衡二叉树(BalancedBinaryTree)平衡二叉树是一种特殊的二叉搜索树,它具有以下特点:每个节点的左子树和右子树的高度差不超过1。所有的子树也都是平衡二叉树。通过保持平衡性,平衡二叉树可以在最坏情况下仍然具有较好的性能,保证查找、插入和删除操作的时间复杂度为O(logn)。......
  • 二叉树 遍历 hdu-1710-Binary Tree Traversals
    给出二叉树的前序遍历和中序遍历,求后序遍历。。 算法:由前序遍历的第一个元素可确定左、右子树的根节点,参照中序遍历又可进一步确定子树的左、右子树元素。如此递归地参照两个遍历序列,最终构造出二叉树。 由前序和中序结果求后序遍历结果树的遍历: 给你一棵树的先......
  • 二叉搜索树(Binary Search Tree,BST)
    二叉搜索树(BinarySearchTree,BST)二叉搜索树(BinarySearchTree),也称二叉查找树或二叉排序树,是一种特殊的二叉树,它满足以下性质对于二叉搜索树的每个节点左子树中的所有节点的值都小于该节点的值右子树中的所有节点的值都大于(或等于)该节点的值对于二叉搜索树的任意节点,其......