题意:
设
f(k)
f
(
k
)
表示在树上任选k个点所组成的最小联通块大小的和。
求出所有
f(k)
f
(
k
)
题解:
这种题一般都单独考虑每个点的贡献。
单点贡献显然就是
Ckn−∑y∈son[x]Cksize[y]
C
n
k
−
∑
y
∈
s
o
n
[
x
]
C
s
i
z
e
[
y
]
k
所以
ans[k]=∑nx=1Ckn−∑y∈son[x]Cksize[y]
a
n
s
[
k
]
=
∑
x
=
1
n
C
n
k
−
∑
y
∈
s
o
n
[
x
]
C
s
i
z
e
[
y
]
k
观察发现无论
k
k
取多少,的系数都是不变的,设为
a[i]
a
[
i
]
ans[k]=∑nia[i]∗Cki
a
n
s
[
k
]
=
∑
i
n
a
[
i
]
∗
C
i
k
这个式子就可以卷积了。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const LL p=924844033,yg=5;
LL n;
struct node{
LL y,next;
}a[400010];LL len=0,last[200010];
LL f[200010],inv[200010],A[800010],B[800010],bin[800010];
void ins(LL x,LL y)
{
a[++len].y=y;
a[len].next=last[x];last[x]=len;
}
void pre()
{
f[0]=f[1]=inv[0]=inv[1]=1;
for(LL i=2;i<=200000;i++) f[i]=f[i-1]*i%p,inv[i]=(p-p/i)*inv[p%i]%p;
for(LL i=2;i<=200000;i++) inv[i]=inv[i-1]*inv[i]%p;
}
LL pow(LL a,LL b)
{
LL ans=1;
while(b)
{
if(b&1) ans=ans*a%p;
a=a*a%p;b>>=1;
}
return ans;
}
LL size[200010];
void ntt(LL *a,LL n,LL op)
{
for(LL i=0;i<n;i++) bin[i]=(bin[i>>1]>>1)|((i&1)*(n>>1));
for(LL i=0;i<n;i++) if(i<bin[i]) swap(a[i],a[bin[i]]);
for(LL i=1;i<n;i<<=1)
{
LL wn=pow(yg,op==1?(p-1)/(2*i):(p-1)-(p-1)/(2*i)),w,t;
for(LL j=0;j<n;j+=i<<1)
{
w=1;
for(LL k=0;k<i;k++)
{
t=a[i+j+k]*w%p;w=w*wn%p;
a[i+j+k]=(a[j+k]-t+p)%p;a[j+k]=(a[j+k]+t)%p;
}
}
}
if(op==-1)
{
LL Inv=pow(n,p-2);
for(LL i=0;i<n;i++) a[i]=a[i]*Inv%p;
}
}
void dfs(LL x,LL fa)
{
size[x]=1;A[n]++;
for(LL i=last[x];i;i=a[i].next)
{
LL y=a[i].y;
if(y==fa) continue;
dfs(y,x);size[x]+=size[y];
A[size[y]]--;
}
if(n-size[x]) A[n-size[x]]--;
}
int main()
{
scanf("%lld",&n);
for(LL i=1;i<n;i++)
{
LL x,y;scanf("%lld %lld",&x,&y);
ins(x,y);ins(y,x);
}
pre();dfs(1,0);
for(LL i=0;i<=n;i++) B[i]=inv[i],A[i]+=A[i]<0?p:0,A[i]=A[i]*f[i]%p;
reverse(B,B+n+1);
LL N=1;while(N<(n+1)<<1) N<<=1;
ntt(A,N,1);ntt(B,N,1);
for(LL i=0;i<N;i++) A[i]=A[i]*B[i]%p;
ntt(A,N,-1);
for(LL i=1;i<=n;i++) printf("%lld\n",inv[i]*A[n+i]%p);
}