【bzoj3451】Tyvj1953 Normal 期望+树的点分治+FFT

题目描述

给你一棵 $n$ 个点的树,对这棵树进行随机点分治,每次随机一个点作为分治中心。定义消耗时间为每层分治的子树大小之和,求消耗时间的期望。

输入

第一行一个整数n,表示树的大小
接下来n-1行每行两个数a,b,表示a和b之间有一条边
注意点是从0开始标号的

输出

一行一个浮点数表示答案
四舍五入到小数点后4位
如果害怕精度跪建议用long double或者extended

样例输入

3
0 1
1 2

样例输出

5.6667


题解

期望+树的点分治+FFT

由于期望可加,因此所求等于 $\sum\limits_{i=1}^n\sum\limits_{j=1}^nP(j在i的点分树子树内)$ 。

而 $j$ 在 $i$ 的点分树子树内,又相当于:$i$ 到 $j$ 的路径上的所有点中(包括 $i$ 和 $j$),$i$ 是第一个选择的。因为如果其它点先被选择则会将 $i$ 与 $j$ 分开,使得 $j$ 不在 $i$ 的点分树内。

这些点中,显然每个点作为第一个选择的点的概率都是相等的,因此概率为 $\frac 1{dis(i,j)}$ ( $dis(i,i)=1$ )。

所求转化为求 $\sum\limits_{i=1}^n\sum\limits_{j=1}^ndis(i,j)$ ,即求距离等于每个值的点对数目。

考虑点分治,每次统计经过根节点路径的答案。dfs一遍子树得出距离等于每个值的点的个数,用容斥(任选两个 - 在同一棵子树内选两个)的方法得出答案。

容易发现求答案的过程实际上就是自身与自身求卷积,因此使用FFT快速求解。

由于距离范围(多项式次数)不会超过子树大小,因此时间复杂度为 $T(n)=O(n\log n)+2(T(\frac n2)+O(\frac n2\log n))=O(n\log^2n)$ 

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 30010
using namespace std;
const double pi = acos(-1);
struct data
{
	double x , y;
	data() {}
	data(double a , double b) {x = a , y = b;}
	data operator+(const data &a)const {return data(x + a.x , y + a.y);}
	data operator-(const data &a)const {return data(x - a.x , y - a.y);}
	data operator*(const data &a)const {return data(x * a.x - y * a.y , x * a.y + y * a.x);}
}A[65550];
int head[N] , to[N << 1] , next[N << 1] , cnt , vis[N] , si[N] , ms[N] , sum , root , deep[N] , val[N] , tot , num[N];
inline void add(int x , int y)
{
	to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void getroot(int x , int fa)
{
	int i;
	si[x] = 1 , ms[x] = 0;
	for(i = head[x] ; i ; i = next[i])
		if(!vis[to[i]] && to[i] != fa)
			getroot(to[i] , x) , si[x] += si[to[i]] , ms[x] = max(ms[x] , si[to[i]]);
	ms[x] = max(ms[x] , sum - si[x]);
	if(ms[x] < ms[root]) root = x;
}
void getdeep(int x , int fa)
{
	int i;
	val[++tot] = deep[x];
	for(i = head[x] ; i ; i = next[i])
		if(!vis[to[i]] && to[i] != fa)
			deep[to[i]] = deep[x] + 1 , getdeep(to[i] , x);
}
void fft(data *a , int n , int flag)
{
	int i , j , k;
	for(i = k = 0 ; i < n ; i ++ )
	{
		if(i > k) swap(a[i] , a[k]);
		for(j = n >> 1 ; (k ^= j) < j ; j >>= 1);
	}
	for(k = 2 ; k <= n ; k <<= 1)
	{
		data wn(cos(2 * pi * flag / k) , sin(2 * pi * flag / k));
		for(i = 0 ; i < n ; i += k)
		{
			data w(1 , 0) , t;
			for(j = i ; j < i + (k >> 1) ; j ++ , w = w * wn)
				t = w * a[j + (k >> 1)] , a[j + (k >> 1)] = a[j] - t , a[j] = a[j] + t;
		}
	}
	if(flag == -1)
		for(i = 0 ; i < n ; i ++ )
			a[i].x /= n;
}
void calc(int flag)
{
	int i , mx = 0 , n = 1;
	for(i = 1 ; i <= tot ; i ++ ) mx = max(mx , val[i]);
	while(n <= 2 * mx) n <<= 1;
	for(i = 0 ; i < n ; i ++ ) A[i].x = A[i].y = 0;
	for(i = 1 ; i <= tot ; i ++ ) A[val[i]].x ++ ;
	fft(A , n , 1);
	for(i = 0 ; i < n ; i ++ ) A[i] = A[i] * A[i];
	fft(A , n , -1);
	for(i = 0 ; i <= 2 * mx ; i ++ ) num[i] += flag * (int)(A[i].x + 0.1);
}
void dfs(int x)
{
	int i;
	vis[x] = 1 , deep[x] = tot = 0 , getdeep(x , 0) , calc(1);
	for(i = head[x] ; i ; i = next[i])
	{
		if(!vis[to[i]])
		{
			deep[to[i]] = 1 , tot = 0 , getdeep(to[i] , 0) , calc(-1);
			sum = si[to[i]] , root = 0 , getroot(to[i] , 0) , dfs(root);
		}
	}
}
int main()
{
	int n , i , x , y;
	long double ans = 0;
	scanf("%d" , &n);
	for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , add(x + 1 , y + 1) , add(y + 1 , x + 1);
	sum = ms[0] = n , root = 0 , getroot(1 , 0) , dfs(root);
	for(i = 0 ; i < n ; i ++ ) ans += (long double)num[i] / (i + 1);
	printf("%.4Lf\n" , ans);
	return 0;
}

 

 

转载于:https://www.cnblogs.com/GXZlegend/p/8611948.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值