AT2064 [AGC005F] Many Easy Problems
https://www.luogu.com.cn/problem/AT2064
考虑每个点
u
u
u对答案的贡献
对于一个
k
k
k
先把
u
u
u设为根
那么它的对答案的贡献就是
(
n
k
)
−
∑
v
∈
s
o
n
[
u
]
(
s
i
z
e
[
v
]
k
)
\binom{n}{k}-\sum_{v\in son[u]}\binom{size[v]}{k}
(kn)−v∈son[u]∑(ksize[v])
然后发现和具体这个节点是什么没有啥关系,只与
s
i
z
e
[
v
]
size[v]
size[v]有关
所以把这个所有儿子的
s
i
z
e
size
size和
n
−
s
i
z
e
[
u
]
n-size[u]
n−size[u]丢进桶里就行了
枚举
s
i
z
e
size
size的大小
a
n
s
[
k
]
=
n
(
n
k
)
−
∑
i
=
k
n
c
n
t
[
i
]
(
i
k
)
ans[k]=n\binom{n}{k}-\sum_{i=k}^{n}cnt[i]\binom{i}{k}
ans[k]=n(kn)−i=k∑ncnt[i](ki)
然后把后面那坨组合数拆开
1
k
!
∑
i
=
k
n
c
n
t
[
i
]
∗
i
!
×
(
i
−
k
)
!
\frac{1}{k!}\sum_{i=k}^n cnt[i]*i!\times(i-k)!
k!1i=k∑ncnt[i]∗i!×(i−k)!
把下标改一下
1
k
!
∑
i
=
0
n
−
k
c
n
t
[
i
+
k
]
∗
(
i
+
k
)
!
×
i
!
\frac{1}{k!}\sum_{i=0}^{n-k} cnt[i+k]*(i+k)!\times i!
k!1i=0∑n−kcnt[i+k]∗(i+k)!×i!
设
f
[
i
]
=
c
n
t
[
i
]
∗
i
!
,
g
[
i
]
=
i
!
f[i]=cnt[i]*i!,g[i]=i!
f[i]=cnt[i]∗i!,g[i]=i!
然后把
f
f
f翻转一下来求差卷积即可
代码不难
code:
#include<bits/stdc++.h>
#define N 800050
#define mod 924844033
using namespace std;
int add(int x, int y) { x += y;
if(x >= mod) x -= mod;
return x;
}
int sub(int x, int y) { x -= y;
if(x < 0) x += mod;
return x;
}
int mul(int x, int y) {
return 1ll * x * y % mod;
}
int qpow(int x, int y) {
int ret = 1;
for(; y; y >>= 1, x = mul(x, x)) if(y & 1) ret = mul(ret, x);
return ret;
}
const int G = 5;
const int Ginv = qpow(G, mod - 2);
int rev[N];
void ntt(int *a, int n, int o) {
for(int i = 1; i < n; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) * (n >> 1));
for(int i = 0; i < n; i ++) if(rev[i] > i) swap(a[i], a[rev[i]]);
for(int len = 2; len <= n; len <<= 1) {
int w0 = qpow((o == 1)? G : Ginv, (mod - 1) / len);
for(int j = 0; j < n; j += len) {
int wn = 1;
for(int k = j; k < j + (len >> 1); k ++, wn = mul(wn, w0)) {
int X = a[k], Y = mul(wn, a[k + (len >> 1)]);
a[k] = add(X, Y), a[k + (len >> 1)] = sub(X, Y);
}
}
}
int ninv = qpow(n, mod - 2);
if(o == -1) for(int i = 0; i < n; i ++) a[i] = mul(a[i], ninv);
}
struct edge {
int v, nxt;
} e[N << 1];
int p[N], eid;
void init() {
memset(p, -1, sizeof p);
eid = 0;
}
void insert(int u, int v) {
e[eid].v = v;
e[eid].nxt = p[u];
p[u] = eid ++;
}
int siz[N], cnt[N], n;
void dfs(int u, int fa) {
siz[u] = 1;
for(int i = p[u]; i + 1; i = e[i].nxt) {
int v = e[i].v;
if(v == fa) continue;
dfs(v, u); siz[u] += siz[v];
cnt[siz[v]] ++;
}
cnt[n - siz[u]] ++;
}
int fac[N], ifac[N];
void init(int n) {
fac[0] = 1;
for(int i = 1; i <= n; i ++) fac[i] = mul(fac[i - 1], i);
ifac[n] = qpow(fac[n], mod - 2);
for(int i = n - 1; i >= 0; i --) ifac[i] = mul(ifac[i + 1], i + 1);
}
int C(int x, int y) {
if(x < y) return 0;
return mul(fac[x], mul(ifac[y], ifac[x - y]));
}
int f[N], g[N];
int main() {
init();
scanf("%d", &n);
for(int i = 1; i < n; i ++) {
int u, v;
scanf("%d%d", &u, &v);
insert(u, v), insert(v, u);
}
dfs(1, 1); init(n);
for(int i = 1; i <= n; i ++) f[i] = mul(cnt[i], fac[i]);
for(int i = 0; i <= n; i ++) g[i] = ifac[i];
reverse(f, f + 1 + n);
int len = 1;
for(; len <= n + n; len <<= 1);
ntt(f, len, 1), ntt(g, len, 1);
for(int i = 0; i < len; i ++) f[i] = mul(f[i], g[i]);
ntt(f, len, - 1);
reverse(f, f + 1 + n);
for(int k = 1; k <= n; k ++) {
printf("%d\n", sub(mul(n, C(n, k)), mul(ifac[k], f[k])));
}
return 0;
}