[BZOJ3451] Normal 题解
这题分三步:葺网(期望)、淀粉质(点分治)、蓉翅(容斥),再佐以芬芳团(FFT),一道巨难无比的 luogu 黑题就诞生了。
期望
先考虑在淀粉树上,\(i\) 点在 \(j\) 点的子树里的概率。实际上这个问题的每种情况相当于是 \(n\) 个点的各种排列方式。这也就相当于,我们在选择 \(j\) 点之前,没有选择路径 \((i,j)\) 上的其他点,那么 \(j\) 的子树内就会包含 \(i\),否则不会。那么 \(i\) 点在 \(j\) 点子树里的概率就是 \(\dfrac 1{dis(i,j)+1}\)。注意,这里的 \(dis(i,j)\) 是边的数量,而不是点的数量。
由于期望具有可加性,所以相当于要求 \(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\dfrac 1{dis(i,j)+1}\)。这玩意可以直接转化为求解 \(num_k=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[dis(i,j)=k]\)。
点分治
此时想到点分治其实水到渠成,关键问题是如何求解。
实际上合并儿子信息的本质就是多项式乘法(因为相当于是两个儿子的信息配对),自然想到 FFT,但是直接把所有都乘到一起正确性会假,用统计“除 \(x\) 子树以外其他子树的信息和”的思想时间复杂度会炸,所以都不行。
容斥
注意力惊人的注意到可以容斥。我们将答案分成两个部分:所有情况(目前考虑的树内的任意两个点可以配对)和错误情况(两个点必须在同一个儿子的子树内),二者相减即为答案。实际上这两个东西都是子树内所有点的深度所得的多项式直接平方的结果。
这样就可以保证在 \(O(m\log m)\) 的时间复杂度内完成合并,加上点分治,时间复杂度为 \(O(n\log^2n)\)。
#include<bits/stdc++.h>
#define stp(x) fixed<<setprecision(x)
using namespace std;
const int N=1e5+5;
const long double pi=acos(-1);
namespace FFT{
struct comn{long double a,b;};
struct dft{vector<comn>fg;};
int rev[N],k,mx=1;
comn operator+(comn x,comn y){
return {x.a+y.a,x.b+y.b};
}comn operator-(comn x,comn y){
return {x.a-y.a,x.b-y.b};
}comn operator*(comn x,comn y){
return {x.a*y.a-x.b*y.b,x.b*y.a+x.a*y.b};
}void operator+=(comn &x,comn y){x=x+y;}
void operator-=(comn &x,comn y){x=x-y;}
void operator*=(comn &x,comn y){x=x*y;}
void init(int n){
k=0,mx=1;
while(mx<=n) mx*=2,k++;
for(int i=0;i<mx;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
}void fft(dft &a,int n,int fl){
for(int i=0;i<n;i++)
if(i<rev[i]) swap(a.fg[i],a.fg[rev[i]]);
comn om={cos(pi),fl*sin(pi)},w={1,0};
for(int i=1;i<n;i*=2,om={cos(pi/i),fl*sin(pi/i)})
for(int j=0;j<n;j+=i*2,w={1,0})
for(int l=j;l<j+i;l++){
comn x=a.fg[l],y=w*a.fg[l+i];
a.fg[l]+=y,a.fg[l+i]=x-y,w*=om;
}
}void sat(dft &x,int len){
while(x.fg.size()<len) x.fg.push_back({0,0});
}void operator+=(dft &x,dft &y){
sat(x,y.fg.size());
for(int i=0;i<y.fg.size();i++) x.fg[i]+=y.fg[i];
}void operator-=(dft &x,dft &y){
for(int i=0;i<y.fg.size();i++) x.fg[i]-=y.fg[i];
}void pow2(dft &x){
int n=x.fg.size();rev[0]=0;
init(n+n),sat(x,mx),fft(x,mx,1);
for(int i=0;i<mx;i++) x.fg[i]*=x.fg[i];
fft(x,mx,-1);
for(int i=0;i<mx;i++) x.fg[i].a/=mx;
}
}using namespace FFT;
int n,dep[N],vis[N],sz[N],num[N];
long double ans;dft sum,c,d,al;vector<int>g[N];
void dfsrt(int x,int fa,int sm,int &rt){
sz[x]=1,num[x]=0;
for(auto y:g[x]){
if(y==fa||vis[y]) continue;
dfsrt(y,x,sm,rt),sz[x]+=sz[y];
num[x]=max(num[x],sz[y]),sz[y]=1;
}num[x]=max(num[x],sm-sz[x]);
if(num[x]<num[rt]) rt=x;
if(sz[x]==sm) sz[x]=1;
}void dfssz(int x,int fa){
for(auto y:g[x])
if(y!=fa&&!vis[y])
dfssz(y,x),sz[x]+=sz[y];
}void dfsp(int x,int fa,dft &id){
id.fg[dep[x]=dep[fa]+1].a++;
for(auto y:g[x])
if(y!=fa&&!vis[y]) dfsp(y,x,id);
}void solve(int x,int sm){
if(sm==1) return al.fg[0].a++,void();
d.fg.clear(),sat(d,sm);int rt=0;
sum.fg.clear(),sat(sum,sm),sum.fg[0].a=1;
dfsrt(x,0,sm,rt),dfssz(rt,0),vis[rt]=1,dep[rt]=0;
for(auto y:g[rt]) if(!vis[y]){
c.fg.clear(),sat(c,sz[y]+2);
dfsp(y,rt,c),sum+=c,pow2(c),d+=c;
}pow2(sum),sum-=d,al+=sum;
for(auto y:g[rt]) if(!vis[y]) solve(y,sz[y]);
}int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n,num[0]=1e9;
for(int i=1,x,y;i<n;i++){
cin>>x>>y,x++,y++;
g[x].push_back(y);
g[y].push_back(x);
}solve(1,n);
for(int i=0;i<n;i++)
ans+=al.fg[i].a/(i+1);
cout<<stp(4)<<ans;
return 0;
}//fast fourier transform
[BZOJ3451] Normal 题解的更多相关文章
- [BZOJ3451]normal 点分治,NTT
[BZOJ3451]normal 点分治,NTT 好久没更博了,咕咕咕. BZOJ3451权限题,上darkbzoj交吧. 一句话题意,求随机点分治的期望复杂度. 考虑计算每个点对的贡献:如果一个点在 ...
- [BZOJ3451]Normal(点分治+FFT)
[BZOJ3451]Normal(点分治+FFT) 题面 给你一棵 n个点的树,对这棵树进行随机点分治,每次随机一个点作为分治中心.定义消耗时间为每层分治的子树大小之和,求消耗时间的期望. 分析 根据 ...
- BZOJ3451 Normal 期望、点分治、NTT
BZOJCH传送门 题目大意:给出一棵树,求对其进行随机点分治的复杂度期望 可以知道一个点的贡献就是其点分树上的深度,也就是这个点在点分树上的祖先数量+1. 根据期望的线性性,考虑一个点对\((x,y ...
- bzoj3451 Normal
题意:点分治每次随机选重心,求期望复杂度. 发现一次点分治的复杂度就是点分树上每个节点的子树大小之和.(并没有发现......) 看这个. 注意这个写法有问题,随便来个菊花图就是n2了. 每一层点分治 ...
- 【BZOJ3451】Normal (点分治)
[BZOJ3451]Normal (点分治) 题面 BZOJ 题解 显然考虑每个点的贡献.但是发现似乎怎么算都不好计算其在点分树上的深度. 那么考虑一下这个点在点分树中每一次被计算的情况,显然就是其在 ...
- 【BZOJ3451】Tyvj1953 Normal 点分治+FFT+期望
[BZOJ3451]Tyvj1953 Normal Description 某天WJMZBMR学习了一个神奇的算法:树的点分治!这个算法的核心是这样的:消耗时间=0Solve(树 a) 消耗时间 += ...
- BZOJ3451: Tyvj1953 Normal
题解: 好神的一道题.蒟蒻只能膜拜题解. 考虑a对b的贡献,如果a是a-b路径上第一个删除的点,那么给b贡献1. 所以转化之后就是求sigma(1/dist(i,j)),orz!!! 如果不是分母的话 ...
- 【BZOJ3451】Normal
[BZOJ3451]Normal Description 某天WJMZBMR学习了一个神奇的算法:树的点分治! 这个算法的核心是这样的: 消耗时间=0 Solve(树 a) 消耗时间 += a 的 大 ...
- BZOJ3451 Tyvj1953 Normal 点分治 多项式 FFT
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ3451.html 题目传送门 - BZOJ3451 题意 给定一棵有 $n$ 个节点的树,在树上随机点分 ...
- BZOJ3451 Tyvj1953 Normal 【期望 + 点分治 + NTT】
题目链接 BZOJ3451 题解 考虑每个点产生的贡献,即为该点在点分树中的深度期望值 由于期望的线性,最后的答案就是每个点贡献之和 对于点对\((i,j)\),考虑\(j\)成为\(i\)祖先的概率 ...
随机推荐
- ThreeJs-05纹理材质高级操作
1.纹理操作 1.1 重复.旋转.位移.缩放 重复 但是要在水平方向上重复,还得允许 按照刚才的重复方式 如果设置为镜像重复 位移 旋转 1.2 翻转与alpha生成颜色 正常的图 不翻转默认是翻转的 ...
- 基于.NET8+Vue3开发的权限管理&个人博客系统
前言 今天大姚给大家分享一个基于.NET8+Vue3开发的权限管理&个人博客系统:Easy.Admin. 项目介绍 Easy.Admin是一个基于.NET8+Vue3+TypeScript开发 ...
- Linux下TCP/IP编程--TCP实战
之前尝试过windows下的简单TCP客户端服务器编写,这次尝试下一下Linux环境下的TCP 客户端代码 #include <stdio.h> #include <stdlib.h ...
- 解决WSL2无法启动提示“找不到元素”
最近一段时间没有看 docker desktop,忽然想起来打开看看,结果死活启动不了.以前卸载之后,重新安装就好了,同样的方法尝试了很多次还是不太行,重启也不行... 后来想想是不是 wsl 出了问 ...
- 基于Java SpringBoot的音乐网站与分享平台
@ 目录 摘要 1. 研究背景 2.研究内容 3.系统功能 3.1前台首页功能模块 3.2在线听歌功能模块 3.3后台登录功能模块 3.4在线听歌管理模块 4.部分功能代码实现 5.源码分享(免费获取 ...
- Springboot上传文件大小限制处理
今天在开发过程中遇到一个文件上传的问题 io.undertow.server.RequestTooBigException: UT000020: Connection terminated as re ...
- 龙哥量化:什么是ZXNH直线拟合指标?ZXNH信号漂移,未来函数检测不到, 函数列表没有,大坑哦哦哦
如果您需要代写技术指标公式, 请联系我. 龙哥QQ:591438821 龙哥微信:Long622889 这个函数太坑, 我也不明白原理是什么, 是未来函数,信号会漂移, zxnh的值只有0和1,下面一 ...
- com.mysql.cj.jdbc.Driver和com.mysql.jdbc.Driver的区别
今天写东西测试的时候发现一个问题,如下: application.yml中数据源是这样配置的: 第一反应就是记忆中连接mysql的驱动不都是com.mysql.jdbc.Driver吗?com.mys ...
- 推荐 5 个 火火火火 的CMS开源.Net项目
下面推荐5个基于.NetCore开发的CMS开源项目. 一.OrchardCore 基于ASP.NET Core 构建的.模块化和多租户应用程序框架,采用文档数据库,非常高性能,跨平台的系统. 1.跨 ...
- IM开发者的零基础通信技术入门(十):零基础,史上最强5G技术扫盲
本文引用了"鲜枣课堂"的<史上最强5G科普>文章内容.为了更好的内容呈现,在引用和收录时内容有改动,转载时请注明原文来源. 1.内容概述 ➊ 5G技术的关注度越来越高: ...