考虑每个点 (x) 对答案的贡献,即总方案数减去不合法方案数,得:
[largeegin{aligned}
f_i&=sum_{x=1}^nleft(inom{n}{i}-sum_{exists e(x,y)} inom{size_y}{i}
ight) \
&=ninom{n}{i}-sum_{x=1}^nsum_{exists e(x,y)} inom{size_y}{i} \
end{aligned}
]
设 (cnt_i) 为子树大小为 (i) 的子树个数,得:
[largeegin{aligned}
f_i&=ninom{n}{i}-sum_{j=i}^n cnt_jinom{j}{i} \
&=ninom{n}{i}-sum_{j=i}^n cnt_jfrac{j!}{i!(j-i)!} \
&=ninom{n}{i}-frac{1}{i!}sum_{j=i}^n frac{cnt_jj!}{(j-i)!} \
&=ninom{n}{i}-frac{1}{i!}sum_{j=0}^{n-i} frac{cnt_{i+j}(i+j)!}{j!} \
end{aligned}
]
发现第二项是一个减法卷积的形式,用 (NTT) 即可求解。
#include<bits/stdc++.h>
#define maxn 800010
#define P 924844033
#define G 5
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
ll n;
ll rev[maxn],f[maxn],g[maxn],fac[maxn],ifac[maxn],siz[maxn],cnt[maxn];
struct edge
{
int to,nxt;
}e[maxn];
int head[maxn],edge_cnt;
void add(int from,int to)
{
e[++edge_cnt]={to,head[from]},head[from]=edge_cnt;
}
ll qp(ll x,ll y)
{
ll v=1;
while(y)
{
if(y&1) v=v*x%P;
x=x*x%P,y>>=1;
}
return v;
}
int calc(int n)
{
int lim=1;
while(lim<=n) lim<<=1;
for(int i=0;i<lim;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)?lim>>1:0);
return lim;
}
void NTT(ll *a,int lim,int type)
{
for(int i=0;i<lim;++i)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int len=1;len<lim;len<<=1)
{
ll wn=qp(G,(P-1)/(len<<1));
for(int i=0;i<lim;i+=len<<1)
{
ll w=1;
for(int j=i;j<i+len;++j,w=w*wn%P)
{
ll x=a[j],y=w*a[j+len]%P;
a[j]=(x+y)%P,a[j+len]=(x-y+P)%P;
}
}
}
if(type==1) return;
ll inv=qp(lim,P-2);
for(int i=0;i<lim;++i) a[i]=a[i]*inv%P;
reverse(a+1,a+lim);
}
void mul(ll *f,ll *g)
{
int lim=calc(n<<1);
NTT(f,lim,1),NTT(g,lim,1);
for(int i=0;i<lim;++i) f[i]=f[i]*g[i]%P;
NTT(f,lim,-1);
}
void dfs(int x,int fa)
{
siz[x]=1;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==fa) continue;
dfs(y,x),siz[x]+=siz[y];
}
cnt[siz[x]]++,cnt[n-siz[x]]++;
}
ll C(ll n,ll m)
{
return fac[n]*ifac[m]%P*ifac[n-m]%P;
}
void init()
{
fac[0]=ifac[0]=1;
for(int i=1;i<=n;++i) fac[i]=fac[i-1]*i%P;
ifac[n]=qp(fac[n],P-2);
for(int i=n-1;i;--i) ifac[i]=ifac[i+1]*(i+1)%P;
}
int main()
{
read(n),init();
for(int i=1;i<n;++i)
{
int x,y;
read(x),read(y);
add(x,y),add(y,x);
}
dfs(1,0),g[0]=1;
for(int i=1;i<=n;++i) f[i]=cnt[n-i]*fac[n-i]%P,g[i]=ifac[i];
mul(f,g),reverse(f,f+n+1);
for(int i=1;i<=n;++i) printf("%lld
",(n*C(n,i)%P-ifac[i]*f[i]%P+P)%P);
return 0;
}