BZOJ3451 Normal 期望、点分治、NTT
题目大意:给出一棵树,求对其进行随机点分治的复杂度期望
可以知道一个点的贡献就是其点分树上的深度,也就是这个点在点分树上的祖先数量+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的更多相关文章
- BZOJ3451 Tyvj1953 Normal 【期望 + 点分治 + NTT】
题目链接 BZOJ3451 题解 考虑每个点产生的贡献,即为该点在点分树中的深度期望值 由于期望的线性,最后的答案就是每个点贡献之和 对于点对\((i,j)\),考虑\(j\)成为\(i\)祖先的概率 ...
- [BZOJ3451]normal 点分治,NTT
[BZOJ3451]normal 点分治,NTT 好久没更博了,咕咕咕. BZOJ3451权限题,上darkbzoj交吧. 一句话题意,求随机点分治的期望复杂度. 考虑计算每个点对的贡献:如果一个点在 ...
- [BZOJ3451]Normal(点分治+FFT)
[BZOJ3451]Normal(点分治+FFT) 题面 给你一棵 n个点的树,对这棵树进行随机点分治,每次随机一个点作为分治中心.定义消耗时间为每层分治的子树大小之和,求消耗时间的期望. 分析 根据 ...
- #565. 「LibreOJ Round #10」mathematican 的二进制(期望 + 分治NTT)
题面 戳这里,题意简单易懂. 题解 首先我们发现,操作是可以不考虑顺序的,因为每次操作会加一个 \(1\) ,每次进位会减少一个 \(1\) ,我们就可以考虑最后 \(1\) 的个数(也就是最后的和) ...
- 【BZOJ3451】Normal (点分治)
[BZOJ3451]Normal (点分治) 题面 BZOJ 题解 显然考虑每个点的贡献.但是发现似乎怎么算都不好计算其在点分树上的深度. 那么考虑一下这个点在点分树中每一次被计算的情况,显然就是其在 ...
- LOJ2541 PKUWC2018猎人杀(概率期望+容斥原理+生成函数+分治NTT)
考虑容斥,枚举一个子集S在1号猎人之后死.显然这个概率是w1/(Σwi+w1) (i∈S).于是我们统计出各种子集和的系数即可,造出一堆形如(-xwi+1)的生成函数,分治NTT卷起来就可以了. #i ...
- 【XSY3306】alpha - 线段树+分治NTT
题目来源:noi2019模拟测试赛(一) 题意: 题解: 这场三道神仙概率期望题……orzzzy 这题暴力$O(n^2)$有30分,但貌似比正解更难想……(其实正解挺好想的) 注意到一次操作实际上就是 ...
- [gdoi2018 day1]小学生图论题【分治NTT】
正题 题目大意 一张随机的\(n\)个点的竞赛图,给出它的\(m\)条相互无交简单路径,求这张竞赛图的期望强联通分量个数. \(1\leq n,m\leq 10^5\) 解题思路 先考虑\(m=0\) ...
- 【BZOJ-3456】城市规划 CDQ分治 + NTT
题目链接 http://www.lydsy.com/JudgeOnline/problem.php?id=3456 Solution 这个问题可以考虑dp,利用补集思想 N个点的简单图总数量为$2^{ ...
随机推荐
- css中那些属性可以被继承
主要的有: 字体相关:line-height, font-family, font-size, font-style, font-variant, font-weight, font 文本相关: le ...
- python联系题1
一.有四个数字:1.2.3.4,能组成多少个互不相同且无重复数字的三位数?各是多少? 程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. # _*_ ...
- MQTT详解以及在IoT中的应用
MQTT定义: MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分.该协议支持所有平台, ...
- MongoDB的基本操作:服务端启动,客户端连接,CRUD操作
本文内容: MongoDB的介绍 MongoDB服务端的启动 MongoDB客户端连接 SQL与MongoDB相关概念解释 什么是BSON 数据库操作 集合操作 文档操作 测试环境:win10 软件版 ...
- Python中列表
names=["Linda","Lily","Lucy","Grace","Paul"] #切片 p ...
- Centos7安装搭建Bugzilla 5.0
1.安装准备: Centos7保证网络连通,如果网络不能连通,可通过配置yum源使用代理服务. vim /etc/yum.conf # The proxy server - proxy server: ...
- Python中DataFrame关联
df = pd.merge( df, # 左 wzplbm, # 右 left_on = ['WZBM','ZBWZMC'], # 左DataFrame匹配列 right_on = ['WZPLBM' ...
- Unity 4.6 GUI
一起来窥探Unity的下一代GUI 预览 UI组件 UI结构 Canvas Button Selection List(滑动列表)
- [MapReduce_add_2] MapReduce 实现年度最高气温统计
0. 说明 编写 MapReduce 程序实现年度最高气温统计 1. 气温数据分析 气温数据样例如下: ++023450FM-+000599999V0202701N015919999999N00000 ...
- Python基础知识:测试代码
1.Python标准库中的模块unittest提供了代码测试工具. 单元测试用于核实函数的某个方面没有问题: 测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求. 通俗的理解 ...