我感觉是很强的一道题……
即使我在刷专题,即使我知道这题是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. 20155202《网络对抗》Exp9 web安全基础实践

    20155202<网络对抗>Exp9 web安全基础实践 实验前回答问题 (1)SQL注入攻击原理,如何防御 SQL注入产生的原因,和栈溢出.XSS等很多其他的攻击方法类似,就是未经检查或 ...

  2. 20155233 《网络对抗技术》EXP3 免杀原理与实践

    正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,自己利用shellcode编程等免杀工具或技巧 使用msf编码器生成jar包 输入命令msfvenom -p ...

  3. 滚动条ScrollViewer防止滚动时按内容跳跃式滚动的设置

    原文:滚动条ScrollViewer防止滚动时按内容跳跃式滚动的设置 属性中将CanContentScroll设置为False,滚动时就不会跳了,会连续的滚动

  4. Kafka查看topic、consumer group状态命令

    最近工作中遇到需要使用kafka的场景,测试消费程序启动后,要莫名的过几十秒乃至几分钟才能成功获取到到topic的partition和offset,而后开始消费数据,于是学习了一下查看kafka br ...

  5. 使用 restTemplate 实现get/post 请求

    get 请求(这里是在 idea 的 test包中,所以需要直接 new RestTemplate() ) 即:RestTemplate restTemplate = new RestTemplate ...

  6. Docker 部署学习

    https://yeasy.gitbooks.io/docker_practice/basic_concept/repository.html https://hujb2000.gitbooks.io ...

  7. Hyperledger Fabric的一些密码学常识

    Hash 哈希(Hash)算法主要作用是将一段任意长度的数据,经过计算转换成一段定长的数据. 这种算法的特性是:几乎不能通过Hash的结果推导出原文.并且几乎没有可能找到两个不同的信息,对两个信息进行 ...

  8. PAT甲题题解-1013. Battle Over Cities (25)-求联通分支个数

    题目就是求联通分支个数删除一个点,剩下联通分支个数为cnt,那么需要建立cnt-1边才能把这cnt个联通分支个数求出来怎么求联通分支个数呢可以用并查集,但并查集的话复杂度是O(m*logn*k)我这里 ...

  9. float和position的使用

    http://blog.csdn.net/yaodebian/article/details/58621183

  10. (第十二周)新功能WBS

    项目名:食物链教学工具 组名:奋斗吧兄弟 组长:黄兴 组员:李俞寰.杜桥.栾骄阳.王东涵 新增加的功能:背景音乐 功能 子功能 二级子功能 预计花费时间(小时) 实际花费时间(小时) 背景音乐 界面组 ...