BZOJCH传送门

题目大意:给出一棵树,求对其进行随机点分治的复杂度期望


可以知道一个点的贡献就是其点分树上的深度,也就是这个点在点分树上的祖先数量+1。

根据期望的线性性,考虑一个点对\((x,y)\)在何时\(x\)能够是\(y\)的祖先,那么在\(x\)到\(y\)的路径上的所有点中\(x\)必须要是第一个被选中的点,否则要么点\(y\)变成点\(x\)的祖先,要么点\(x\)和点\(y\)会被分在不同的子树中。那么我们要求的就是\(\sum \frac{1}{dis_{x,y}}\),其中\(dis_{x,y}\)表示\(x\)到\(y\)路径上的点的数量。直接使用\(NTT\)统计路径长度即可。

注意在某一个分治中心进行合并时必须按照深度从小到大合并,否则复杂度是不正确的。

#include<bits/stdc++.h>
#define INF 0x7fffffff
using namespace std; inline int read(){
int a = 0;
char c = getchar();
while(!isdigit(c))
c = getchar();
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return a;
} const int MAXN = 1e5 + 10 , MOD = 998244353 , G = 3 , INV = 332748118;
struct Edge{
int end , upEd;
}Ed[MAXN << 1];
int head[MAXN] , ind[MAXN] , size[MAXN] , ans[MAXN];
int N , need , nSize , mSize , mInd , cntEd;
bool vis[MAXN];
long long inv_need;
vector < vector < int > > v; inline void addEd(int a , int b){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
} inline int poww(long long a , int b){
int times = 1;
while(b){
if(b & 1)
times = times * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return times;
} void NTT(vector < int > &v , int type){
for(int i = 0 ; i < need ; ++i)
if(i < ind[i])
swap(v[i] , v[ind[i]]);
for(int i = 1 ; i < need ; i <<= 1){
int wn = poww(type == 1 ? G : INV , (MOD - 1) / (i << 1));
for(int j = 0 ; j < need ; j += i << 1){
long long w = 1;
for(int k = 0 ; k < i ; ++k , w = w * wn % MOD){
int x = v[j + k] , y = v[i + j + k] * w % MOD;
v[j + k] = x + y >= MOD ? x + y - MOD : x + y;
v[i + j + k] = x < y ? x - y + MOD : x - y;
}
}
}
} void getSize(int x){
vis[x] = 1;
++nSize;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end])
getSize(Ed[i].end);
vis[x] = 0;
} void getRoot(int x){
vis[x] = 1;
int maxN = 0;
size[x] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end]){
getRoot(Ed[i].end);
maxN = max(maxN , size[Ed[i].end]);
size[x] += size[Ed[i].end];
}
maxN = max(maxN , nSize - size[x]);
if(maxN < mSize){
mSize = maxN;
mInd = x;
}
vis[x] = 0;
} void calc(vector < int > &v , int x , int l){
while(v.size() <= l)
v.push_back(0);
++v[l];
vis[x] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end])
calc(v , Ed[i].end , l + 1);
vis[x] = 0;
} bool cmp(vector < int > a , vector < int > b){
return a.size() < b.size();
} void solve(int x){
nSize = 0;
mSize = INF;
getSize(x);
getRoot(x);
x = mInd;
vis[x] = 1;
v.clear();
vector < int > cur , ano;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end]){
cur.clear();
calc(cur , Ed[i].end , 1);
v.push_back(cur);
}
cur.clear();
sort(v.begin() , v.end());
need = 1;
for(int i = 0 ; i < v.size() ; ++i){
while(need < cur.size() + v[i].size())
need <<= 1;
inv_need = poww(need , MOD - 2);
for(int j = 1 ; j < need ; ++j)
ind[j] = (ind[j >> 1] >> 1) | (j & 1 ? need >> 1 : 0);
while(cur.size() < need)
cur.push_back(0);
while(v[i].size() < need)
v[i].push_back(0);
ano.clear();
NTT(cur , 1);
NTT(v[i] , 1);
for(int j = 0 ; j < need ; ++j){
ano.push_back(1ll * cur[j] * v[i][j] % MOD);
cur[j] = cur[j] + v[i][j] >= MOD ? cur[j] + v[i][j] - MOD : cur[j] + v[i][j];
}
NTT(ano , -1);
NTT(cur , -1);
for(int j = 0 ; j < need ; ++j){
ans[j] += ano[j] * inv_need % MOD;
cur[j] = cur[j] * inv_need % MOD;
}
while(cur.back() == 0)
cur.pop_back();
}
for(int i = 1 ; i < need ; ++i)
ans[i] += cur[i];
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end])
solve(Ed[i].end);
} int main(){
N = read();
for(int i = 1 ; i < N ; ++i){
int a = read() , b = read();
addEd(a , b);
addEd(b , a);
}
solve(1);
long double sum = 0;
for(int i = 1 ; i <= N ; ++i)
sum += ans[i] * 2.0 / (i + 1);
cout << fixed << setprecision(4) << sum + N;
return 0;
}

BZOJ3451 Normal 期望、点分治、NTT的更多相关文章

  1. BZOJ3451 Tyvj1953 Normal 【期望 + 点分治 + NTT】

    题目链接 BZOJ3451 题解 考虑每个点产生的贡献,即为该点在点分树中的深度期望值 由于期望的线性,最后的答案就是每个点贡献之和 对于点对\((i,j)\),考虑\(j\)成为\(i\)祖先的概率 ...

  2. [BZOJ3451]normal 点分治,NTT

    [BZOJ3451]normal 点分治,NTT 好久没更博了,咕咕咕. BZOJ3451权限题,上darkbzoj交吧. 一句话题意,求随机点分治的期望复杂度. 考虑计算每个点对的贡献:如果一个点在 ...

  3. [BZOJ3451]Normal(点分治+FFT)

    [BZOJ3451]Normal(点分治+FFT) 题面 给你一棵 n个点的树,对这棵树进行随机点分治,每次随机一个点作为分治中心.定义消耗时间为每层分治的子树大小之和,求消耗时间的期望. 分析 根据 ...

  4. #565. 「LibreOJ Round #10」mathematican 的二进制(期望 + 分治NTT)

    题面 戳这里,题意简单易懂. 题解 首先我们发现,操作是可以不考虑顺序的,因为每次操作会加一个 \(1\) ,每次进位会减少一个 \(1\) ,我们就可以考虑最后 \(1\) 的个数(也就是最后的和) ...

  5. 【BZOJ3451】Normal (点分治)

    [BZOJ3451]Normal (点分治) 题面 BZOJ 题解 显然考虑每个点的贡献.但是发现似乎怎么算都不好计算其在点分树上的深度. 那么考虑一下这个点在点分树中每一次被计算的情况,显然就是其在 ...

  6. LOJ2541 PKUWC2018猎人杀(概率期望+容斥原理+生成函数+分治NTT)

    考虑容斥,枚举一个子集S在1号猎人之后死.显然这个概率是w1/(Σwi+w1) (i∈S).于是我们统计出各种子集和的系数即可,造出一堆形如(-xwi+1)的生成函数,分治NTT卷起来就可以了. #i ...

  7. 【XSY3306】alpha - 线段树+分治NTT

    题目来源:noi2019模拟测试赛(一) 题意: 题解: 这场三道神仙概率期望题……orzzzy 这题暴力$O(n^2)$有30分,但貌似比正解更难想……(其实正解挺好想的) 注意到一次操作实际上就是 ...

  8. [gdoi2018 day1]小学生图论题【分治NTT】

    正题 题目大意 一张随机的\(n\)个点的竞赛图,给出它的\(m\)条相互无交简单路径,求这张竞赛图的期望强联通分量个数. \(1\leq n,m\leq 10^5\) 解题思路 先考虑\(m=0\) ...

  9. 【BZOJ-3456】城市规划 CDQ分治 + NTT

    题目链接 http://www.lydsy.com/JudgeOnline/problem.php?id=3456 Solution 这个问题可以考虑dp,利用补集思想 N个点的简单图总数量为$2^{ ...

随机推荐

  1. 【读书笔记】iOS-storyboard-两个场景间的切换(二)

    接着上一节 一,在storybord画布上面,新增加一个场景,即拖动一个View Controller到画布上面,同时建立一个button,名字为secondButton.如图所示. 二,点击第一个按 ...

  2. What I am concerned about

    redux: https://www.cnblogs.com/XieJunBao/p/9232341.html vuex: https://juejin.im/post/5a8eb24e6fb9a06 ...

  3. Android studio 在一个项目上添加另一个项目,引用其内部参数

    Setting.gradle 里面 添加 include ':app',‘imagePicker’ 其中 imagePicker 为要引入的项目名 build.gradle(Module: app)  ...

  4. 安卓界面之Toolbar上手

    一.在配置文件采用自定义Style方法去除Actionbar <resources> <style name="MyTheme" parent="The ...

  5. C# JObject和JArray 的分享

    最近在调用别人的搜索引擎接口时遇到了一种返回类型为数组的情况,如 {  "result": [     //根据用户输入搜索匹配到的标题数组         "我是一条新 ...

  6. maven五:查找jar包坐标,选择jar包版本

    查找jar包坐标 以spring core的jar包为例,访问http://www.mvnrepository.com/    在最上方中间,输入spring core,点击Search. 搜索结果第 ...

  7. Logstash收集nginx访问日志和错误日志

    1.收集访问日志 1).首先是要在nginx里面配置日志格式化输出 log_format main "$http_x_forwarded_for | $time_local | $reque ...

  8. 30个最常用的Linux系统命令行

    1.cd命令这是一个非常基本,也是大家经常需要使用的命令,它用于切换当前目录,它的参数是要切换到的目录的路径,可以是绝对路径,也可以是相对路径.如:cd /root/Docements # 切换到目录 ...

  9. 如何快速搭建&配置本地服务器-前端技能

    废话不多说,上图: 首先登录http://www.phpstudy.net/download.html 下载安装phpstudy,特别简单不详解: 创建一个本机项目并且与本机域名进行绑定主要分为两步; ...

  10. 改变javascript函数内部this指针指向的三种方法

    在查了大量的资料后,我总结了下面的三条规则,这三条规则,已经可以解决目前我所遇到的所有问题.规则0:函数本身是一个特殊类型,大多数时候,可以认为是一个变量. function a() { alert( ...