【BZOJ 3451】Tyvj1953 Normal 思维题+期望概率+FFT+点分治
我感觉是很强的一道题……
即使我在刷专题,即使我知道这题是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+点分治的更多相关文章
- bzoj 3451: Tyvj1953 Normal [fft 点分治 期望]
3451: Tyvj1953 Normal 题意: N 个点的树,点分治时等概率地随机选点,代价为当前连通块的顶点数量,求代价的期望值 百年难遇的点分治一遍AC!!! 今天又去翻了一下<具体数学 ...
- BZOJ 3451: Tyvj1953 Normal 点分治+FFT
根据期望的线性性,我们算出每个点期望被计算次数,然后进行累加. 考虑点 $x$ 对点 $y$ 产生了贡献,那么说明 $(x,y)$ 之间的点中 $x$ 是第一个被删除的. 这个期望就是 $\frac{ ...
- 【BZOJ 3811】玛里苟斯 大力观察+期望概率dp+线性基
大力观察:I.从输出精准位数的约束来观察,一定会有猫腻,然后仔细想一想,就会发现输出的时候小数点后面不是.5就是没有 II.从最后答案小于2^63可以看出当k大于等于3的时候就可以直接搜索了 期望概率 ...
- 3451: Tyvj1953 Normal 点分治 FFT
国际惯例的题面:代价理解为重心和每个点这个点对的代价.根据期望的线性性,我们枚举每个点,计算会产生的ij点对的代价即可.那么,i到j的链上,i必须是第一个被选择的点.对于i来说,就是1/dis(i,j ...
- BZOJ 3270 博物馆 && CodeForces 113D. Museum 期望概率dp 高斯消元
大前提,把两个点的组合看成一种状态 x 两种思路 O(n^7) f[x]表示在某一个点的前提下,这个状态经过那个点的概率,用相邻的点转移状态,高斯一波就好了 O(n^6) 想象成臭气弹,这个和那个的区 ...
- bzoj 3727: Final Zadanie 思维题
题目: Description 吉丽YY了一道神题,题面是这样的: "一棵n个点的树,每条边长度为1,第i个结点居住着a[i]个人.假设在i结点举行会议,所有人都从原住址沿着最短路径来到i结 ...
- BZOJ3451: Tyvj1953 Normal
题解: 好神的一道题.蒟蒻只能膜拜题解. 考虑a对b的贡献,如果a是a-b路径上第一个删除的点,那么给b贡献1. 所以转化之后就是求sigma(1/dist(i,j)),orz!!! 如果不是分母的话 ...
- 【BZOJ 3925】[Zjoi2015]地震后的幻想乡 期望概率dp+状态压缩+图论知识+组合数学
神™题........ 这道题的提示......(用本苣蒻并不会的积分积出来的)并没有 没有什么卵用 ,所以你发现没有那个东西并不会 不影响你做题 ,然后你就可以推断出来你要求的是我们最晚挑到第几大的 ...
- 【BZOJ3451】Tyvj1953 Normal 点分治+FFT+期望
[BZOJ3451]Tyvj1953 Normal Description 某天WJMZBMR学习了一个神奇的算法:树的点分治!这个算法的核心是这样的:消耗时间=0Solve(树 a) 消耗时间 += ...
随机推荐
- 20155317王新玮《网络对抗技术》实验8 WEB基础实践
20155317王新玮<网络对抗技术>实验8 WEB基础实践 一.实验准备 1.0 实验目标和内容 Web前端HTML.能正常安装.启停Apache.理解HTML,理解表单,理解GET与P ...
- 2017-2018-2 《网络对抗技术》 20155319 第二周 Exp1 PC平台逆向破解(5)M
2017-2018-2 <网络对抗技术> 20155319 第二周 Exp1 PC平台逆向破解(5)M 一.实践目标 1.1实践介绍 本次实践的对象是一个名为pwn1的linux可执行文件 ...
- Exp1 PC平台逆向破解(5)M
Exp1 PC平台逆向破解(5)M [ 直接修改程序机器指令,改变程序执行流程] 用命令cp pwn1 20155320备份pwn1 输入objdump -d 20155320反汇编,找到call指令 ...
- NetWork——描述一次完整的网络请求过程
台根DNS,根DNS服务器收到请求后会返回负责这个域名(.net)的服务器的一个IP,本地DNS服务器使用该IP信息联系负责.net域的这台服务器.这台负责.net域的服务器收到请求后,如果自己无法解 ...
- springboot的热部署和dubug
采用了项目聚合,产生一些不同,遇到的问题和解决方法分享下. 项目结构: rebuilder2 -htran 主项目 -htran-api 1.htran.pom <parent> < ...
- [ZJOI2018]保镖
[ZJOI2018]保镖 Tags:题解 题意 链接 初始在平面上有一些点,九条可怜随机出现在一个矩形内的任意一点.若九条可怜出现在\(O\)点,则平面上所有的点都从\(P_i\)移动到\(P'_i\ ...
- 微信小程序云开发之云函数创建
云函数 云函数是一段运行在云端的代码,无需管理服务器,在开发工具内编写.一键上传部署即可运行后端代码. 小程序内提供了专门用于云函数调用的 API.开发者可以在云函数内使用 wx-server-sdk ...
- Java 多线程(四)之守护线程(Daemon)
目录 定义 如何创建 判断 注意事项 函数setDaemon(true)必须在 start() 函数之前使用. 守护线程中产生的线程也是守护线程: 测试 @ 定义 Java 中有两种线程: 一种是用户 ...
- 软件测试_测试工具_Loadrunner_IP欺骗
一.设置IP欺骗的原因: 1.当某个IP的访问过于频繁或者访问量过大时,服务器会拒绝访问请求: 2.某些服务器配置了负载均衡,使用同一个IP不能测出系统的实际性能.Loadrunner中的IP欺骗通过 ...
- [Latex] 所有字体embedded: Type3 PDF文档处理 / True Type转换为Type 1
目录: [正文] Adobe Acrobat打印解决字体嵌入问题 [Appendix I] Type3转TRUE Type/Type 1 [Appendix II] TRUE Type转Type 1 ...