我感觉是很强的一道题……
即使我在刷专题,即使我知道这题是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. # 《网络对抗》Exp1 PC平台逆向破解20155337祁家伟

    <网络对抗>Exp1 PC平台逆向破解20155337祁家伟 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会 ...

  2. Vue 项目集合

    饿了么安全应急响应中心 饿了么招聘 饿了么前端 · GitHub 稀土掘金 异乡好居 明星垂搜 广州建管 基于Vue.js的数据统计系统(一) 基于Vue.js的数据统计系统(二) 基于Vue.js的 ...

  3. POJ 1459&&3436

    两道比较基础的网络流题目,重点就是建图. 1458:题意就是给你一些东西它们的数据,其中一些是发电站,还有一些是用户的家里,其中还有一些是中转站.让你求最大的输送电量. 就是一道很基础的最大流题目,建 ...

  4. vector 去重

    1.使用unique函数: sort(v.begin(),v.end()); v.erase(unique(v.begin(), v.end()), v.end()); //unique()函数将重复 ...

  5. libgdx学习记录24——九宫格NinePatch

    NinePatch用于图片纹理拉伸显示.当图片拉伸时,4个角不会拉伸,而只有中间的部分会拉伸,适合做圆角矩形类的Button. 简单示例: package com.fxb.newtest; impor ...

  6. 算法练习-002-返回一个set数组

    题目描述: 写一个函数,它的作用是接受一个整数(假设为num),返回一个数组,数组的长度为num, 数组中的内容为随机的0至(num-1)的值,并且不能重复.比如num为5的话,数组可能是[1,0,3 ...

  7. java File读取文件始终不存在的问题分析

    先上图: 如图,f1 始终能读到该文件,使用的是绝对路径 f2 却是相对路径. 感觉很奇怪,明明一模一样的代码为什么会产生不同的结果呢? 首先想到的是是不是有什么特殊字符.. 拿到notepad++中 ...

  8. stl源码剖析 详细学习笔记 算法(1)

    //---------------------------15/03/27---------------------------- //算法 { /* 质变算法:会改变操作对象之值 所有的stl算法都 ...

  9. Microsoft Dynamics CRM 常用JS语法(已转成vs2017语法提示)

    背景 最近接触到Microsoft Dynamics CRM的开发.前端js是必不可少的部分,奈何没有一个语法提示,点不出来后续的语句. 在vscode上面搜索插件的时候发现,有一个大神写的插件htt ...

  10. numpy 初识(一)

    基本操作: 读取文件(与pandas读取csv相似): import numpy numpy.genfromtxt("word.txt", delimiter=',', dtype ...