【BZOJ3451】Normal
【BZOJ3451】Normal
Description
某天WJMZBMR学习了一个神奇的算法:树的点分治!
这个算法的核心是这样的:
消耗时间=0
Solve(树 a)
消耗时间 += a 的 大小
如果 a 中 只有 1 个点
退出
否则在a中选一个点x,在a中删除点x
那么a变成了几个小一点的树,对每个小树递归调用Solve
我们注意到的这个算法的时间复杂度跟选择的点x是密切相关的。
如果x是树的重心,那么时间复杂度就是O(nlogn)
但是由于WJMZBMR比较傻逼,他决定随机在a中选择一个点作为x!
Sevenkplus告诉他这样做的最坏复杂度是O(n^2)
但是WJMZBMR就是不信>_<。。。
于是Sevenkplus花了几分钟写了一个程序证明了这一点。。。你也试试看吧_
现在给你一颗树,你能告诉WJMZBMR他的傻逼算法需要的期望消耗时间吗?(消耗时间按在Solve里面的那个为标准)
Input
第一行一个整数n,表示树的大小
接下来n-1行每行两个数a,b,表示a和b之间有一条边
注意点是从0开始标号的
Output
一行一个浮点数表示答案
四舍五入到小数点后4位
如果害怕精度跪建议用long double或者extended
Sample Input
3
0 1
1 2
Sample Output
5.6667
题目大意就是给定一棵树,问随机进行点分治(不一定找重心)每个节点期望访问次数之和。
神题啊。
我们考虑计算点对\(P_{x,y}\)表示在\(x\)最为点分重心的时候访问了\(y\)的概率,由期望的线性性得出\(ans=\sum_{x=1}^n\sum_{y=1}^n P_{x,y}\)。
然后我们考虑怎么求这个\(P_{x,y}\)。假设\(x\)到\(y\)最短路上有\(ver_{x,y}\)个点,那么概率就是\(\frac{1}{ver_{x,y}}\)。
为什么呢?我们可以考虑将点分看成一个删点的操作。我们必须保证在删除\(x\)之前\(x\)到\(y\)的路径都是未被删除的。我们假设可以重复删除以删除的点,则:
\begin{align}
P_{x,y}&=\sum_{i=0}^{\infty}(\frac{n-ver_{x,y}}{n})^i\frac{1}{n}\\
&
=\frac{1}{1-\frac{n-ver_{x,y}}{n}}\frac{1}{n}\\
&=\frac{1}{ver_{x,y}}
\end{align}
\]
这个公式的意义就是考虑在删除\(x\)之前删除了多少次其他点。
所以我们要求的就是\(ans=ans=\sum_{x=1}^n\sum_{y=1}^n \frac{1}{ver_{x,y}}\)
因为这个公式是非线性的,所以我们对于每个\(k\)要求出\([ver_{x,y}==k]\)的数量。这个我们就可以考虑点分治了。
#include<bits/stdc++.h>
#define ll long long
#define N 30005
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int n;
struct Com {
	long double r,v;
	Com() {r=v=0;}
	Com(double a,double b) {r=a,v=b;}
};
Com operator +(const Com &a,const Com &b) {return Com(a.r+b.r,a.v+b.v);}
Com operator -(const Com &a,const Com &b) {return Com(a.r-b.r,a.v-b.v);}
Com operator *(const Com &a,const Com &b) {return Com(a.r*b.r-a.v*b.v,a.r*b.v+a.v*b.r);}
Com operator /(const Com &a,const long double b) {return Com(a.r/b,a.v/b);}
const double pi=acos(-1);
void FFT(Com *a,int d,int flag) {
	int n=1<<d;
	static int rev[N<<2];
	for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<d-1);
	for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
	for(int s=1;s<=d;s++) {
		int len=1<<s,mid=len>>1;
		Com w(cos(2*flag*pi/len),sin(2*flag*pi/len));
		for(int i=0;i<n;i+=len) {
			Com t(1,0);
			for(int j=0;j<mid;j++,t=t*w) {
				Com u=a[i+j],v=a[i+j+mid]*t;
				a[i+j]=u+v;
				a[i+j+mid]=u-v;
			}
		}
	}
	if(flag==-1) for(int i=0;i<n;i++) a[i]=a[i]/n;
}
struct road {
	int to,nxt;
}s[N<<1];
int h[N],cnt;
void add(int i,int j) {s[++cnt]=(road) {j,h[i]};h[i]=cnt;}
int size[N],mx[N],sum,rt;
int fr[N];
bool vis[N];
void Get_root(int v,int fr) {
	mx[v]=size[v]=1;
	::fr[v]=fr;
	for(int i=h[v];i;i=s[i].nxt) {
		int to=s[i].to;
		if(to==fr||vis[to]) continue ;
		Get_root(to,v);
		size[v]+=size[to];
		mx[v]=max(mx[v],size[to]);
	}
	mx[v]=max(mx[v],sum-size[v]);
	if(mx[rt]>mx[v]) rt=v;
}
int ans[N];
int tem[N];
int mxdep;
void statis(int v,int fr,int dep) {
	tem[dep]++;
	mxdep=max(mxdep,dep);
	for(int i=h[v];i;i=s[i].nxt) {
		int to=s[i].to;
		if(to==fr||vis[to]) continue ;
		statis(to,v,dep+1);
	}
}
Com A[N<<2];
void cal(int flag) {
	int d=ceil(log2(mxdep<<1|1));
	for(int i=0;i<1<<d;i++) A[i]=Com(tem[i],0);
	FFT(A,d,1);
	for(int i=0;i<1<<d;i++) A[i]=A[i]*A[i];
	FFT(A,d,-1);
	for(int i=0;i<1<<d;i++) {
		ans[i+1]+=flag*(int(A[i].r+0.5));
	}
}
void solve(int v) {
	vis[v]=1;
	if(fr[v]) size[fr[v]]=sum-size[v];
	mxdep=0;
	for(int i=h[v];i;i=s[i].nxt) {
		int to=s[i].to;
		if(vis[to]) continue ;
		statis(to,v,1);
	}
	ans[1]++;
	for(int i=1;i<=mxdep;i++) ans[i+1]+=tem[i]*2;
	cal(1);
	for(int i=1;i<=mxdep;i++) tem[i]=0;
	for(int i=h[v];i;i=s[i].nxt) {
		int to=s[i].to;
		if(vis[to]) continue ;
		mxdep=0;
		statis(to,v,1);
		cal(-1);
		for(int j=1;j<=mxdep;j++) tem[j]=0;
		sum=size[to];
		rt=0;
		Get_root(to,v);
		solve(rt);
	}
}
int main() {
	mx[0]=1e9;
	n=Get();
	int a,b;
	for(int i=1;i<n;i++) {
		a=Get()+1,b=Get()+1;
		add(a,b),add(b,a);
	}
	sum=n;
	Get_root(1,0);
	solve(rt);
	long double Ans=0;
	for(int i=1;i<=n;i++) {
		Ans+=1.0*ans[i]/(1.0*i);
	}
	cout<<fixed<<setprecision(4)<<Ans;
	return 0;
}
【BZOJ3451】Normal的更多相关文章
- 【BZOJ3451】Normal (点分治)
		[BZOJ3451]Normal (点分治) 题面 BZOJ 题解 显然考虑每个点的贡献.但是发现似乎怎么算都不好计算其在点分树上的深度. 那么考虑一下这个点在点分树中每一次被计算的情况,显然就是其在 ... 
- 【BZOJ3451】Tyvj1953 Normal 点分治+FFT+期望
		[BZOJ3451]Tyvj1953 Normal Description 某天WJMZBMR学习了一个神奇的算法:树的点分治!这个算法的核心是这样的:消耗时间=0Solve(树 a) 消耗时间 += ... 
- 【bzoj3451】Tyvj1953 Normal  期望+树的点分治+FFT
		题目描述 给你一棵 $n$ 个点的树,对这棵树进行随机点分治,每次随机一个点作为分治中心.定义消耗时间为每层分治的子树大小之和,求消耗时间的期望. 输入 第一行一个整数n,表示树的大小接下来n-1行每 ... 
- 【BZOJ3451】Tyvj1953 Normal - 点分治+FFT
		题目来源:NOI2019模拟测试赛(七) 非原题面,题意有略微区别 题意: 吐槽: 心态崩了. 好不容易场上想出一题正解,写了三个小时结果写了个假的点分治,卡成$O(n^2)$ 我退役吧. 题解: 原 ... 
- 【原】Coursera—Andrew Ng机器学习—Week 2 习题—Linear Regression with Multiple Variables 多变量线性回归
		Gradient Descent for Multiple Variables [1]多变量线性模型 代价函数 Answer:AB [2]Feature Scaling 特征缩放 Answer:D ... 
- 【概率论】5-10:二维正态分布(The Bivariate Normal Distributions)
		title: [概率论]5-10:二维正态分布(The Bivariate Normal Distributions) categories: - Mathematic - Probability k ... 
- 【概率论】5-6:正态分布(The Normal Distributions Part III)
		title: [概率论]5-6:正态分布(The Normal Distributions Part III) categories: - Mathematic - Probability keywo ... 
- 【概率论】5-6:正态分布(The Normal Distributions Part II)
		title: [概率论]5-6:正态分布(The Normal Distributions Part II) categories: - Mathematic - Probability keywor ... 
- 【概率论】5-6:正态分布(The Normal Distributions Part I)
		title: [概率论]5-6:正态分布(The Normal Distributions Part I) categories: - Mathematic - Probability keyword ... 
随机推荐
- 有关于MVC SignalR的问题
			刚拜读 @Learning hard 的 [Asp.net 开发系列之SignalR篇]专题一:Asp.net SignalR快速入门 跟着博文一步步操作,这是新人的学习方式 然而笔者的开发环境和 @ ... 
- tomcat域名绑定设置
			域名绑定分为单域名绑定.多域名绑定,配置主要涉及到tomcat目录下conf/server.xml文件 一.单域名绑定 1.修改server.xml 大约105行的内容(不是必须修改,如果只是绑定一个 ... 
- java_自定义标签运行原理
			一.自定义标签运行原理: 二.文字说明 1.IE->web服务器 2.Web服务器->jsp 3.遇到自定义标签,首先实例化标签所对应的标签处理器类 4.调用setPageContext方 ... 
- 获取请求的ip工具类
			package com.example.util; import javax.servlet.http.HttpServletRequest; /** * get remote msg * 获取访问的 ... 
- 照葫芦画瓢系列之Java --- Maven的配置
			一.Maven仓库分类 Maven中,仓库只分为两类:本地仓库和远程仓库.当Maven根据坐标寻找构件的时候,它首先去查看本地仓库,如果本地仓库有此构件,则直接使用,如果本地仓库不存在此构件,或者需要 ... 
- SQL分组函数
			分组函数是对表中的多行进行操作,而每组返回一个计算结果.常用的分组函数包括: 函数 语法格式 函数描述以及注意事项 AVG AVG([distinct|all] expr) 返回一个数字列或计算列的平 ... 
- Android为TV端助力 SharedPreferences 轻量级存储!
			首先在当前进程也就是当前的项目里面进行存储 SharedPreferences.Editor editor = mContext.getSharedPreferences("tvplay&q ... 
- 函数纹理(国际象棋棋盘纹理&粗布纹理)MFC
			函数纹理(国际象棋棋盘纹理&粗布纹理)MFC实现 源码百度云下载 国际象棋棋盘纹理(效果图见最后) //国际象棋纹理函数 //g(u, v) = a , 向下取整(8u)+向下取整(8v) ... 
- java基础(五)  String性质深入解析
			引言 本文将讲解String的几个性质. 一.String的不可变性 对于初学者来说,很容易误认为String对象是可以改变的,特别是+链接时,对象似乎真的改变了.然而,String对象一经创 ... 
- Azure SQL Virtual Machine报Login failed for user 'NT Service\SqlIaaSExtension'. Reason: Could not find a login matching the name provided
			在一台位于HK的Azure SQL Virtual Machine上修改排序规则,重建系统数据库后,监控发现大量的登录失败告警生成,如下所示: DESCRIPTION: Login failed f ... 
