【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\)的路径都是未被删除的。我们假设可以重复删除以删除的点,则:

\[\displaystyle
\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的更多相关文章

  1. 【BZOJ3451】Normal (点分治)

    [BZOJ3451]Normal (点分治) 题面 BZOJ 题解 显然考虑每个点的贡献.但是发现似乎怎么算都不好计算其在点分树上的深度. 那么考虑一下这个点在点分树中每一次被计算的情况,显然就是其在 ...

  2. 【BZOJ3451】Tyvj1953 Normal 点分治+FFT+期望

    [BZOJ3451]Tyvj1953 Normal Description 某天WJMZBMR学习了一个神奇的算法:树的点分治!这个算法的核心是这样的:消耗时间=0Solve(树 a) 消耗时间 += ...

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

    题目描述 给你一棵 $n$ 个点的树,对这棵树进行随机点分治,每次随机一个点作为分治中心.定义消耗时间为每层分治的子树大小之和,求消耗时间的期望. 输入 第一行一个整数n,表示树的大小接下来n-1行每 ...

  4. 【BZOJ3451】Tyvj1953 Normal - 点分治+FFT

    题目来源:NOI2019模拟测试赛(七) 非原题面,题意有略微区别 题意: 吐槽: 心态崩了. 好不容易场上想出一题正解,写了三个小时结果写了个假的点分治,卡成$O(n^2)$ 我退役吧. 题解: 原 ...

  5. 【原】Coursera—Andrew Ng机器学习—Week 2 习题—Linear Regression with Multiple Variables 多变量线性回归

    Gradient Descent for Multiple Variables [1]多变量线性模型  代价函数 Answer:AB [2]Feature Scaling 特征缩放 Answer:D ...

  6. 【概率论】5-10:二维正态分布(The Bivariate Normal Distributions)

    title: [概率论]5-10:二维正态分布(The Bivariate Normal Distributions) categories: - Mathematic - Probability k ...

  7. 【概率论】5-6:正态分布(The Normal Distributions Part III)

    title: [概率论]5-6:正态分布(The Normal Distributions Part III) categories: - Mathematic - Probability keywo ...

  8. 【概率论】5-6:正态分布(The Normal Distributions Part II)

    title: [概率论]5-6:正态分布(The Normal Distributions Part II) categories: - Mathematic - Probability keywor ...

  9. 【概率论】5-6:正态分布(The Normal Distributions Part I)

    title: [概率论]5-6:正态分布(The Normal Distributions Part I) categories: - Mathematic - Probability keyword ...

随机推荐

  1. 【Java每日一题】20170206

    20170120问题解析请点击今日问题下方的“[Java每日一题]20170206”查看(问题解析在公众号首发,公众号ID:weknow619) package Feb2017; public cla ...

  2. go里面的指针用法

    什么是指针 指针是存储一个变量的内存地址的变量. 在上图中,变量 b 的值是 156,存储在地址为 0x1040a124 的内存中.变量 a 存储了变量 b 的地址.现在可以说 a 指向 b. 指针的 ...

  3. HDU3038(KB5-D加权并查集)

    How Many Answers Are Wrong Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  4. 7;XHTML表单

    1.表单的功能结构 2.文本栏.密码栏.隐藏栏 3.复选栏.单选栏 4.窗体栏位.区块栏位 5.按钮.图像按钮 6.允许上传文件 7.表单的外框和标题 8.元件的次序和快捷键 表单是提供让读者在网页上 ...

  5. windows for windows:下载、安装

    关于docker的下载:同学们不要再网上找来找去了,直接去到阿里云下载客户端,配置阿里的国内镜像地址就好~ 申请一个阿里云的账号,然后: tips:如果使用虚拟机的os 是windows 那么很抱歉, ...

  6. iPhone手机怎么投屏到电脑 airplay在哪里设置

    iPhone手机怎么投屏到电脑?想要小屏转大屏,其实方法很简单,简单几步就可以操作,下面简单几步教大家手机投屏电脑的方法. 使用工具: Iphone&电脑 操作方法: 1.如果想要把手机本地的 ...

  7. SAP FI配置步骤

    http://blog.sina.com.cn/s/blog_8eda1a620100uwzj.html No. 配置对象 事务代码 配置内容 路径 备注 1 定义公司 OX15 企业结构>定义 ...

  8. 用ABP只要加人即可马上加快项目进展(二) - 分工篇

    2018年和1998年其中两大区别就是: 前端蓬勃发展, 前后端分离是一个十分大的趋势. 专门的测试人员角色被取消, 多出了一个很重要的角色, 产品经理   ABP只要加入即可马上加快项目进展, 选择 ...

  9. Linux PCI设备驱动的实现思路与思想

    概述 1.PCI设备一般都具有双重身份,一方面作为PCI设备注册到Linux内核,另一方面,作为字符设备或者块设备,或者网络设备注册到Linux内核,所以,在看PCI设备时一定要注意到这点. 2. 一 ...

  10. 判断字符串a和b是否互为旋转词

    旋转词:把字符串str的任意部分移动到后面形成的新字符串叫做字符串str的旋转词. 比如abc的旋转词有 abc,acb,cba,... 判断str1和str2是否互为旋转词,其最优解可以是时间复杂度 ...