Description

给定一棵以 \(1\) 为根 \(n\) 个节点的树。

定义 \(f(k)\) :从树上等概率随机选出 \(k\) 个节点,这 \(k\) 个点的虚树大小的期望。

一个点 \(x\) 在这些被选出的 \(k\) 个点的虚树上,当且仅当它满足下列条件至少一个:

  • \(x\) 被选出。
  • 存在两个被选出的节点 \(a,b\),使得 \(\operatorname{lca}(a,b)=x\)。

给定 \(m\),求 \(f(1),f(2),\cdots,f(m)\)。 对 \(998244353\) 取模。\(n\leq 4\cdot 10^5\)。

Sol

又是套着期望皮的计数题。

对于每个点 \(i\) 求出有多少种方案对答案有贡献即可:

  • \(i\) 被选出,总方案数为 \(C(n-1,k-1)\) 。
  • \(i\) 至少两个儿子的子树中存在被选出的点。

第二种不太好算,考虑用总方案数减去不合法的方案数。

总方案数就是 \(C(n-1,k)\)。

如果点 \(i\) 的子树中没有被选中的,方案数为 \(C(n-sze[i],k)\)。

只有一个儿子的子树中有被选中的,可以枚举儿子 \(j\),方案数就是 \(\sum\limits_{j} C(n-sze[i]+sze[j],k)\)。

注意到这样的话,\(i\) 子树中没有被选中的方案数被多算了 儿子个数次,所以还需要加上 \(son[i]\times C(n-sze[i],k)\)。

所以

\[f(k)=\sum\limits_{i=1}^n C_{n-1}^{k-1}+C_{n-1}^k+(son[i]-1)\times C_{n-sze[i]}^k-\sum_j C_{n-sze[i]+sze[j]}^k
\]

\[f(k)=\sum\limits_{i=1}^n C_{n}^{k}+(son[i]-1)\times C_{n-sze[i]}^k-\sum_j C_{n-sze[i]+sze[j]}^k
\]

如何对于每个 \(k\) 快速求呢?

观察到式子中的每一项组合数的上标都是 \(k\),所以我们可以开个桶 \(buc[i]\),在形如 \(buc[n-sze[i]]\) 的地方加上 \(son[i]+1\),在 \(buc[n-sze[i]+sze[j]]\) 处 \(-1\)。

好处就是,再推一步式子:

\[f(k)=\sum_{i=0}^n buc[i]\cdot C_i^k
\]

这就是个卷积的形式,\(\mathbf{NTT}\)优化就吼了。

Code

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using std::min;
using std::max;
using std::swap;
using std::vector;
typedef double db;
typedef long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define all(A) A.begin(),A.end()
#define mp(A,B) std::make_pair(A,B)
const int N=2e6+5;
const int mod=998244353; int son[N],sze[N],buc[N];
int n,m,cnt,head[N],fac[N];
int a[N],b[N],lim,rev[N],ifac[N]; struct Edge{
int to,nxt;
}edge[N<<1]; void add(int x,int y){
edge[++cnt].to=y;
edge[cnt].nxt=head[x];
head[x]=cnt;
} int ksm(int a,int b=mod-2,int ans=1){
while(b){
if(b&1) ans=1ll*ans*a%mod;
a=1ll*a*a%mod;b>>=1;
} return ans;
} void ntt(int *f,int g){
for(int i=1;i<lim;i++) if(i<rev[i]) swap(f[i],f[rev[i]]);
for(int mid=1;mid<lim;mid<<=1){
int tmp=ksm(g,(mod-1)/(mid<<1));
for(int R=mid<<1,j=0;j<lim;j+=R){
for(int w=1,k=0;k<mid;k++,w=1ll*w*tmp%mod){
int x=f[j+k],y=1ll*w*f[j+k+mid]%mod;
f[j+k]=(x+y)%mod,f[j+k+mid]=(mod+x-y)%mod;
}
}
} if(g>3)
for(int in=ksm(lim),i=0;i<lim;i++) f[i]=1ll*f[i]*in%mod;
} int getint(){
int X=0,w=0;char ch=getchar();
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=X*10+ch-48,ch=getchar();
if(w) return -X;return X;
} void init(int n){
fac[0]=ifac[0]=1;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;
ifac[n]=ksm(fac[n]);
for(int i=n-1;i;i--) ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
} void dfs(int now,int fa=0){
sze[now]=1; int tot=0; buc[n]++;
for(int i=head[now];i;i=edge[i].nxt){
int to=edge[i].to;
if(sze[to]) continue;
tot++; dfs(to,now);
sze[now]+=sze[to];
}
for(int i=head[now];i;i=edge[i].nxt){
int to=edge[i].to;
if(to==fa) continue;
(buc[n-sze[now]+sze[to]]+=mod-1)%=mod;
} (buc[n-sze[now]]+=tot-1+mod)%=mod;
} int C(int n,int m){
if(n<m) return 0;
return 1ll*ifac[n]*fac[m]%mod*fac[n-m]%mod;
} signed main(){
n=getint(),m=getint(),init(N-5);
for(int i=1;i<n;i++){
int x=getint(),y=getint();
add(x,y),add(y,x);
} dfs(1);
lim=1;while(lim<=n+n) lim<<=1;
for(int i=1;i<lim;i++) rev[i]=(rev[i>>1]>>1)|(i&1?lim>>1:0);
for(int i=0;i<=n;i++)
a[n-i]=1ll*buc[i]*fac[i]%mod,
b[i]=ifac[i];
ntt(a,3),ntt(b,3);
for(int i=0;i<lim;i++) a[i]=1ll*a[i]*b[i]%mod;
ntt(a,(mod+1)/3);
for(int i=1;i<=m;i++)
printf("%lld\n",1ll*a[n-i]*ifac[i]%mod*C(n,i)%mod);
return 0;
}

[EOJ629] 两开花的更多相关文章

  1. 解题:AT2064 Many Easy Problems&EXNR #1 T3 两开花

    题面 两道题比较像,放在一起写了,后者可以看成前者的加强版 (sto ztb orz) 先看AT那道题 考虑计算每个点的贡献,用容斥计算:每个点没有贡献当且仅当选的所有点都在以他为根时的一个子节点的子 ...

  2. THU-CCF WC2019两开花记

    今年年初,清华大学举办的THUWC2019即将正式开启,我将继续扮演蒟蒻OIER,努力创造一个菜鸡的形象,THU-CCF WC两爆炸,笑掉各位大牙,大家多多关注. Day0 广州好热啊╰(‵□′)╯! ...

  3. 【巨杉数据库SequoiaDB】企业级和开源领域“两开花”,巨杉引领国产数据库创新

    2019年12月15日,OSC 源创会·年终盛典在深圳圆满举行.巨杉数据库作为业界领先的金融级分布式数据库厂商, 获得 “2019年开源数据库先锋企业” 及 “2019 GVP-Gitee最有价值开源 ...

  4. 为什么需要Docker?

    前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 估计大家也可能听过Docker这项技术(在论坛上.招 ...

  5. [转帖]Windows 上面IE的历史

    微软向Chrome举手投降 这么多代IE你都用过吗 2019年04月20日 18:48 4030 次阅读 稿源:太平洋电脑网 2 条评论 这个清明假节,很多人过得波澜不惊,然而一个曾被万千网民挂在口中 ...

  6. 前后端交互实现(nginx,json,以及datatable的问题相关)

    1.同源问题解决 首先,在同一个域下搭建网络域名访问,需要nginx软件,下载之后修改部分配置 然后再终端下cmd  nginx.exe命令,或者打开nginx.exe文件,会运行nginx一闪而过, ...

  7. OO第二次博客作业(第二单元总结)

    在我开始写这次博客作业的时候,窗外响起了希望之花,由此联想到乘坐自己写的电梯FROM-3-TO--1下楼洗澡,然后······ 开个玩笑,这么辣鸡的电梯肯定不会投入实际使用的,何况只是一次作业.还是从 ...

  8. 【CZYZ 20160819】背包

    题目描述 蛤布斯有nn个物品和一个大小为mm的背包,每个物品有大小和价值,它希望你帮它求出背包里最多能放下多少价值的物品. 输入数据 第一行两个整数 n,mn,m. 接下来 nn 行每行两个整数 xi ...

  9. WC2019 划水记

    写在前面: 本篇是擅长咕咕咕的\(\text{BLUESKY007}\)同学难得不咕写的游记,将会记录\(WC2019(2019.1.24(Day\ 0)\sim2019.1.30(Day\ 6))\ ...

随机推荐

  1. 第44章:MongoDB-集群--Sharding(分片)--分片的片键选择

    ①片键选择的重要性 所谓片键,就是用来拆分数据的字段,通常为1-2个字段,由于片键一旦确定,并已经分片过后,基本上就不可能再修改片键了,因此初期设计和选择就非常重要了 ②片键规则 1:不可以是数组 2 ...

  2. 第二次OO总结

    作业5——多线程电梯 好像失忆了,竟然对这三部电梯很陌生,我尽量回忆一下当时挣扎的场景orz 整体思路和第二次电梯差不多,但是将调度器类套在了电梯类里 优点可能是没有无效,足矣!!!缺点emmmm要是 ...

  3. ASP.NET代码调用SQL Server带DateTime类型参数的存储过程抛出异常问题

    ASP.NET代码调用SQL Server带DateTime类型参数的存储过程,如果DateTime类型参数的值是'0001/1/1 0:00:00'时,就会抛出异常“Message: SqlDate ...

  4. Exp3 免杀原理与实践_05齐帅

    Exp3 免杀原理与实践 20154305_齐帅 想要弄懂免杀,一定得先把基础问题弄明白啊~~ 一.基础问题回答 (1)杀软是如何检测出恶意代码的? - -检测特征码: 依靠分析总结出计算机病毒中常出 ...

  5. 逻辑回归 vs 决策树 vs 支持向量机(I)

    原文链接:http://www.edvancer.in/logistic-regression-vs-decision-trees-vs-svm-part1/ 分类问题是我们在各个行业的商业业务中遇到 ...

  6. Base64格式上传文件至阿里云(java)

    Controller @PostMapping("/save") public R save(@RequestBody ShareEntity share){ OSSClient ...

  7. window系统中 mongodb创建用户名和密码

    use admindb.createUser({user:"root",pwd:"root",roles:[{"role":"us ...

  8. Solidity: ParserError: Expected pragma, import directive or contract/interface/library definition.

    第一行忘记加分号 pragma solidity ^0.4.0;

  9. visual studio 2015 Opencv 3.4.0配置

    因为想做AR方面,需要了解计算机视觉知识,决定从opencv开始入门,在网上买了本毛星云的<Opencv3编程入门>开始自学. 一.opencv 3.4.0下载安装 在官网http://o ...

  10. day_12函数默认值,数据类型的补充,函数对象名称空间与作用域,函数的嵌套定义

    复习, 昨天讲了字符串的比较,按照从左往右比较每一个字符,通过字符对应的ASCII码进行比较 函数的参数,‘ 实参与形参 形参:在函数定义时()中出现的参数 实参,在函数调用时()中出现的参数 实参的 ...