Problem Statement
One day, Takahashi was given the following problem from Aoki:
- You are given a tree with N vertices and an integer K. The vertices are numbered 1 through N. The edges are represented by pairs of integers (ai,bi).
- For a set S of vertices in the tree, let f(S) be the minimum number of the vertices in a subtree of the given tree that contains all vertices in S.
- There are
ways to choose K vertices from the trees. For each of them, let S be the set of the chosen vertices, and find the sum of f(S) over all
ways.
- Since the answer may be extremely large, print it modulo 924844033(prime).
Since it was too easy for him, he decided to solve this problem for all K=1,2,…,N.
Constraints
- 2≦N≦200,000
- 1≦ai,bi≦N
- The given graph is a tree.
Input
The input is given from Standard Input in the following format:
N
a1 b1
a2 b2
:
aN−1 bN−1
Output
Print N lines. The i-th line should contain the answer to the problem where K=i, modulo 924844033.
Sample Input 1
3
1 2
2 3
Sample Output 1
3
7
3
The diagram above illustrates the case where K=2. The chosen vertices are colored pink, and the subtrees with the minimum number of vertices are enclosed by red lines.
Sample Input 2
4
1 2
1 3
1 4
Sample Output 2
4
15
13
4
Sample Input 3
7
1 2
2 3
2 4
4 5
4 6
6 7
Sample Output 3
7
67
150
179
122
45
7
考虑每条边的贡献,对于k==i的答案显然会贡献 C(n,i) - C(s,i) - C(n-s,i) ,其中s是边一端的子树大小。
这玩意暴力算显然是 O(N^2) 的,想一想还可以怎么优化。
显然每条边的第一项 C(n,i) 是常量,我们最后对于每个i加上即可;
后面的组合数可以拆成 阶乘和阶乘的逆的乘积的形式,所以我们就可以构造两个多项式:
A = ∑ cnt[s] * x^s (cnt[s] 是 子树大小为s的子树个数)
B = Σ 1/(i!) * x^(-i)
这两个多项式卷出来就可以得到每个k==i的答案(别忘了每个位置再乘一个阶乘的逆元)
(只有我一个人被模数坑了吗QWQ)
/*
对于一条把树分成s和n-s的边
C(s,k) -> s! / k! / (s-k)!
C(n-s,k) -> (n-s)! / k! / (n-s-k)!
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=600005,ha=924844033,root=5;
inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;}
inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;}
inline int ksm(int x,int y){
int an=1;
for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
return an;
}
int jc[maxn+5],ni[maxn+5],n,m,ans,to[maxn*2],ne[maxn*2],num,inv;
int a[maxn+5],b[maxn+5],r[maxn+5],siz[maxn+5],hd[maxn],N,l,INV;
inline void addline(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;}
inline int C(int x,int y){ return x<y?0:jc[x]*(ll)ni[y]%ha*(ll)ni[x-y]%ha;}
inline void init(){
jc[0]=1;
for(int i=1;i<=maxn;i++) jc[i]=jc[i-1]*(ll)i%ha;
ni[maxn]=ksm(jc[maxn],ha-2);
for(int i=maxn;i;i--) ni[i-1]=ni[i]*(ll)i%ha;
}
void dfs(int x,int fa){
siz[x]=1;
for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa) dfs(to[i],x),siz[x]+=siz[to[i]];
if(x!=1) ADD(a[siz[x]],jc[siz[x]]),ADD(a[n-siz[x]],jc[n-siz[x]]);
}
inline void NTT(int *c,int f){
for(int i=0;i<N;i++) if(i<r[i]) swap(c[i],c[r[i]]);
for(int i=1;i<N;i<<=1){
int omega=ksm(f==1?root:inv,(ha-1)/(i<<1));
for(int j=0,P=i<<1;j<N;j+=P){
int now=1;
for(int k=0;k<i;k++,now=now*(ll)omega%ha){
int x=c[j+k],y=c[j+k+i]*(ll)now%ha;
c[j+k]=add(x,y);
c[j+k+i]=add(x,ha-y);
}
}
}
if(f==-1) for(int i=0;i<N;i++) c[i]=c[i]*(ll)INV%ha;
}
inline void solve(){
dfs(1,1);
for(int i=0;i<n;i++) b[n-i]=ni[i];
for(N=1;N<=(2*n);N<<=1) l++;
for(int i=0;i<N;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
NTT(a,1),NTT(b,1);
for(int i=0;i<N;i++) a[i]=a[i]*(ll)b[i]%ha;
INV=ksm(N,ha-2),NTT(a,-1);
for(int i=1;i<=n;i++) a[i+n]=add(ha-a[i+n]*(ll)ni[i]%ha,C(n,i)*(ll)n%ha);
}
int main(){
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
init(),inv=ksm(5,ha-2);
scanf("%d",&n);
int uu,vv;
for(int i=1;i<n;i++) scanf("%d%d",&uu,&vv),addline(uu,vv),addline(vv,uu);
solve();
for(int i=1;i<=n;i++) printf("%d
",a[i+n]);
return 0;
}