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. 更改MAC地址,突破公司绑定MAC地址的限制

    步骤/方法 1 打开开始菜单,选择控制面板. 2   3 打开控制面板项,选择网络和共享中心. 4   5 选择更改适配器设置. 6   7 选择本地要修改MAC地址的网卡. 8   9 右键该网卡, ...

  2. java.exe

    进程:是一个正在执行中的程序.每一个进程执行都有一个执行顺序.该顺序是一个执行路径,或者叫一个控制单元. 线程(例:FlashGet):就是进程中一个独立的控制单元.线程在控制着进程的执行.一个进程中 ...

  3. shell 命令 创建/删除 软连接 ln -s

    软链接的作用是, 1. 节省复制造成的空间浪费 2. 保证两个文件的内容同时修改 所以,可以把软连接理解为给文件/文件夹创建了别名,当访问别名时,实际访问的是链接的文件/文件夹 软链文件 ln -s ...

  4. js数组中容易误用的一些方法

    1.every和some 两个方法的参数都是一个函数,函数的有3个参数,依次是当前值value,索引index,数组array every判断数据中的每一项是否满足某个条件,如果满足就返回true,有 ...

  5. tomcat服务器怎样远程调试

    适合windows系统 1.首先tomcat/bin目录下startup.bat打开最前面添加以下代码: SET CATALINA_OPTS=-server -Xdebug -Xnoagent -Dj ...

  6. JSTL标签库的基本教程之核心标签库(二)

    JSTL标签库的基本教程之核心标签库(二) 核心标签库 标签 描述 <c:out> 用于在JSP中显示数据,就像<%= ... > <c:set> 用于保存数据 & ...

  7. Git使用详细教程(4):git rm使用详解

    我们使用git rm 文件名来进行删除文件的操作. git rm index.php这个命令把工作区的index.php删除并暂存了. 如何撤回已暂存的删除命令? 上图中已经给出了提示,使用git r ...

  8. Shiro基础

    Factory<T>接口(org.apache.shiro.util.Factory) 接口的getInstance()方法是泛型方法,可以用来创建SecurityManager接口对象 ...

  9. git常用命令总结——你一定会用到的几个命令

    git入门看廖雪峰大神的教程即可,通俗易懂:      https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b806 ...

  10. Kali学习笔记27:Burpsuite(上)

    文章的格式也许不是很好看,也没有什么合理的顺序 完全是想到什么写一些什么,但各个方面都涵盖到了 能耐下心看的朋友欢迎一起学习,大牛和杠精们请绕道 如果我只能选择一款工具进行Web渗透,那么一定就是Bu ...