我感觉是很强的一道题……
即使我在刷专题,即使我知道这题是fft+点分治,我仍然做不出来……
可能是知道是fft+点分治限制了我的思路???(别做梦了,再怎样也想不出来的……)
我做这道题的话,一看就想单独算每个点的贡献,一开始想算每个点深度的期望,后来又想算每个点的点分树子树大小的期望,再后来就想利用点分治,于是就想算每个联通块的贡献,后来就想怂了……
开始说这道题的做法……
我们不算每个点的贡献,算每个点对的贡献!!!
我们想啊,显然,每个点的点分树子树大小的期望加和就是答案,然而呢,对于一个点,其点分树子树大小的期望就是其他点存在于其点分树子树内的概率加和,这样我们算出每个点对(i,j)i存在于j的子树的概率然后加和就好了!!!
然而怎么快速计算每个点对(i,j)i存在于j的子树的概率呢?我们仔细想一想什么情况下在点分树中j是i的祖先,就是在i到j的路径上的所有点中,j是第一个被删除的点,那么这个概率是多少呢?是1/(dis(i,j)+1),为什么呢?因为在i到j的路径上的所有点中,每个点是第一个被删除的概率是相等的(仔细想一想就会发现是这样的).
现在问题好办了,我们只要统计出每一种距离的点对个数就好了,这是一个很简单的点分治的问题,处理的时候要用fft优化一下.
感觉这道题里把n变成n^2的思想,或者说统计点对的思想,是很好很优秀的.
这道题给我的一个很大的启发就是——思维是主体,算法是工具.

#include <cmath>
#include <cstdio>
#include <cstring>
#include <complex>
#include <algorithm>
typedef double db;
typedef std::complex<db> cd;
const int N=,Inf=0x3f3f3f3f;
const db Pai=acos(-.);
int dis[N<<],num[N<<],cnt,deep[N<<],max_deep,tmp[N<<];
int max,root,size[N];
bool vis[N];
int rev[N<<],len;
cd A[N<<],B[N<<];
inline void fft(cd *C,int opt){
register int i,j,k;cd temp;
for(i=;i<len;++i)if(rev[i]>i)std::swap(C[i],C[rev[i]]);
for(k=;k<=len;k<<=){
cd wn(cos(*opt*Pai/k),sin(*opt*Pai/k));
for(i=;i<len;i+=k){
cd w(.,.);
for(j=;j<(k>>);++j,w*=wn){
temp=w*C[i+j+(k>>)];
C[i+j+(k>>)]=(C[i+j]-temp);
C[i+j]+=temp;
}
}
}
}
inline void mul(int *a,int *b,int *c,int n){
len=;while(len<n)len<<=;int i;
for(i=;i<len;++i)rev[i]=(rev[i>>]>>)|((i&)?(len>>):);
for(i=;i<len;++i)A[i]=a[i],B[i]=b[i];
fft(A,),fft(B,);
for(i=;i<len;++i)A[i]*=B[i];
fft(A,-);db inv=./len;
for(i=;i<len;++i)c[i]=round(A[i].real()*inv);
}
struct V{
int to,next;
}c[N<<];
int head[N],t;
inline void add(int x,int y){
c[++t].to=y,c[t].next=head[x],head[x]=t;
}
int n;
inline void dfs1(int x,int fa,int sum){
int temp=;size[x]=;
for(int i=head[x];i;i=c[i].next)
if(c[i].to!=fa&&!vis[c[i].to]){
dfs1(c[i].to,x,sum);
size[x]+=size[c[i].to];
temp=std::max(temp,size[c[i].to]);
}
temp=std::max(temp,sum-size[x]);
if(temp<=max)max=temp,root=x;
}
inline void dfs2(int x,int fa,int d){
++deep[d],max_deep=std::max(max_deep,d);
for(int i=head[x];i;i=c[i].next)
if(c[i].to!=fa&&!vis[c[i].to])
dfs2(c[i].to,x,d+);
}
inline void dfs(int x,int sum){
max=Inf,root=,dfs1(x,,sum);
int i,j;num[]=,vis[root]=true;
for(i=head[root];i;i=c[i].next)
if(!vis[c[i].to]){
dfs2(c[i].to,,);
for(j=;j<=max_deep;++j)
num[j]+=deep[j],tmp[j]=deep[j],deep[j]=;
cnt=std::max(cnt,max_deep);
mul(tmp,tmp,tmp,max_deep+max_deep+);
for(j=;j<=(max_deep<<);++j)
dis[j]-=tmp[j],tmp[j]=;
max_deep=;
}
for(i=;i<=cnt;++i)
tmp[i]=num[i],num[i]=;
mul(tmp,tmp,tmp,cnt+cnt+);
for(i=;i<=(cnt<<);++i)
dis[i]+=tmp[i],tmp[i]=;
cnt=;
for(i=head[x=root];i;i=c[i].next)
if(!vis[c[i].to])
dfs(c[i].to,size[c[i].to]<size[x]?size[c[i].to]:sum-size[x]);
}
int main(){
scanf("%d",&n);
int i,x,y;
for(i=;i<n;++i){
scanf("%d%d",&x,&y);
++x,++y,add(x,y),add(y,x);
}
dfs(,n);
db ans=.;
for(i=;i<n;++i)
ans+=(db)dis[i]/(db)(i+);
printf("%.4f\n",ans);
return ;
}

【BZOJ 3451】Tyvj1953 Normal 思维题+期望概率+FFT+点分治的更多相关文章

  1. bzoj 3451: Tyvj1953 Normal [fft 点分治 期望]

    3451: Tyvj1953 Normal 题意: N 个点的树,点分治时等概率地随机选点,代价为当前连通块的顶点数量,求代价的期望值 百年难遇的点分治一遍AC!!! 今天又去翻了一下<具体数学 ...

  2. BZOJ 3451: Tyvj1953 Normal 点分治+FFT

    根据期望的线性性,我们算出每个点期望被计算次数,然后进行累加. 考虑点 $x$ 对点 $y$ 产生了贡献,那么说明 $(x,y)$ 之间的点中 $x$ 是第一个被删除的. 这个期望就是 $\frac{ ...

  3. 【BZOJ 3811】玛里苟斯 大力观察+期望概率dp+线性基

    大力观察:I.从输出精准位数的约束来观察,一定会有猫腻,然后仔细想一想,就会发现输出的时候小数点后面不是.5就是没有 II.从最后答案小于2^63可以看出当k大于等于3的时候就可以直接搜索了 期望概率 ...

  4. 3451: Tyvj1953 Normal 点分治 FFT

    国际惯例的题面:代价理解为重心和每个点这个点对的代价.根据期望的线性性,我们枚举每个点,计算会产生的ij点对的代价即可.那么,i到j的链上,i必须是第一个被选择的点.对于i来说,就是1/dis(i,j ...

  5. BZOJ 3270 博物馆 && CodeForces 113D. Museum 期望概率dp 高斯消元

    大前提,把两个点的组合看成一种状态 x 两种思路 O(n^7) f[x]表示在某一个点的前提下,这个状态经过那个点的概率,用相邻的点转移状态,高斯一波就好了 O(n^6) 想象成臭气弹,这个和那个的区 ...

  6. bzoj 3727: Final Zadanie 思维题

    题目: Description 吉丽YY了一道神题,题面是这样的: "一棵n个点的树,每条边长度为1,第i个结点居住着a[i]个人.假设在i结点举行会议,所有人都从原住址沿着最短路径来到i结 ...

  7. BZOJ3451: Tyvj1953 Normal

    题解: 好神的一道题.蒟蒻只能膜拜题解. 考虑a对b的贡献,如果a是a-b路径上第一个删除的点,那么给b贡献1. 所以转化之后就是求sigma(1/dist(i,j)),orz!!! 如果不是分母的话 ...

  8. 【BZOJ 3925】[Zjoi2015]地震后的幻想乡 期望概率dp+状态压缩+图论知识+组合数学

    神™题........ 这道题的提示......(用本苣蒻并不会的积分积出来的)并没有 没有什么卵用 ,所以你发现没有那个东西并不会 不影响你做题 ,然后你就可以推断出来你要求的是我们最晚挑到第几大的 ...

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

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

随机推荐

  1. 20155204 王昊《网络对抗技术》EXP4

    20155204 王昊<网络对抗技术>EXP4 一.实验后回答问题 (1)如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有 ...

  2. 20155336 虎光元《网络攻防》Exp2后门原理与实践

    20155336 虎光元<网络攻防>Exp2后门原理与实践 一.实验内容 (1)使用netcat获取主机操作Shell,cron启动 (0.5分) (2)使用socat获取主机操作Shel ...

  3. 【arm学习】我的第一个裸板程序

    初学ARM感觉写个裸板程序还真的不容易,可能是没有用到ADS,keil之类的开发平台的缘故吧.编译,链接过程在linux平台上完成,这样学起来更有实感,还能顺便熟悉linux环境,以及命令,何乐而不为 ...

  4. 阿里云Redis外网转发访问

    1.前提条件 如果您需要从本地 PC 端访问 Redis 实例进行数据操作,可以通过在 ECS 上配置端口映射或者端口转发实现.但必须符合以下前提条件: 若 Redis 实例属于专有网络(VPC),E ...

  5. github协同开发

    看官请移步GitHub团队项目合作流程 本文是上述链接的截图,担心哪天作者不小心删除了,备一份在自己这里,仅为自己看着方便.侵权请告知

  6. jQuery .attr() vs. .prop()

    Property vs. Attribute 在开始正式比较prop()和attr()两个jQuery方法之前,我们有必要先弄清一下Property和Attribute两个单词的意思.在中文里面,它们 ...

  7. pandas 初识(三)

    Python Pandas 空值 pandas 判断指定列是否(全部)为NaN(空值) import pandas as pd import numpy as np df = pd.DataFrame ...

  8. jmeter实战1

  9. 代理神器allproxy

    背景 allproxy意为all as proxy,即是说所有设备均可以成为一个网络代理,唯一的要求就是有网络访问权限. 一般的代理软件要求宿主机必须有公网地址,然后才能把网络代理出去,但在实际情况下 ...

  10. 利用HOG+SVM实现行人检测

    利用HOG+SVM实现行人检测 很久以前做的行人检测,现在稍加温习,上传记录一下. 首先解析视频,提取视频的每一帧形成图片存到磁盘.代码如下 import os import cv2 videos_s ...