题面
给定一棵树,定义 f ( i ) f(i) f(i) 表示对于每个大小为 i i i 的点集,能够包含它的最小连通块的大小之和。
你的目的是对于每个 i ∈ [ 1 , n ] i\in[1,n] i∈[1,n],求出 f ( i ) f(i) f(i)。
你需要对所有答案取模 924844033 924844033 924844033(一个质数)。
Input
格式如下:
N N N
a 1 a_1 a1 b 1 b_1 b1
a 2 a_2 a2 b 2 b_2 b2
: : :
a N − 1 a_{N-1} aN−1 b N − 1 b_{N-1} bN−1
( a i , b i ) (a_i,b_i) (ai,bi) 表示树上的一条边。
Output
输出 n n n 行,第 i i i 行输出一个整数 f ( i ) f(i) f(i)。
Sample 1
Input
3
1 2
2 3
Output
3
7
3
Sample 2
Input
4
1 2
1 3
1 4
Output
4
15
13
4
Sample 3
Input
7
1 2
2 3
2 4
4 5
4 6
6 7
Output
7
67
150
179
122
45
7
Constriants
对于 100 % 100 \% 100% 的数据, 2 ≤ n ≤ 2 × 1 0 5 2\le n\le 2\times 10^5 2≤n≤2×105。
题解
首先,拿到一个奇怪模数先解构
924844033
=
441
×
2
21
+
1
P
r
i
m
i
t
i
v
e
r
o
o
t
(
924844033
)
=
5
924844033=441\times2^{21}+1\\ \mathrm{Primitiveroot}(924844033)=5
924844033=441×221+1Primitiveroot(924844033)=5
唔~~~
好的我们继续分析。
包含住一个子图的最小连通块大小,直接来看根本不可做,但是由于是棵树,所以该连通块其实可以通过在原树上删夷枝叶把该连通块裁剪出来。按照这个思路计算贡献,一个点集的贡献其实是总点数
n
n
n 减 不在连通块中的点数。再换个思路,我们可以通过枚举「不在连通块中的点」来统计各个大小点集的答案,若以某个点
x
x
x 为根时,某个儿子
y
y
y 子树大小为
s
i
z
[
y
]
siz[y]
siz[y] ,那么将对点集大小为
1
,
2
,
3
,
.
.
.
1,2,3,...
1,2,3,... 的答案依次贡献
(
n
−
s
i
z
[
y
]
1
)
,
(
n
−
s
i
z
[
y
]
2
)
,
(
n
−
s
i
z
[
y
]
3
)
,
.
.
.
{n-siz[y]\choose 1},{n-siz[y]\choose 2},{n-siz[y]\choose 3},...
(1n−siz[y]),(2n−siz[y]),(3n−siz[y]),... 。我们不如此时将
f
[
n
−
s
i
z
[
y
]
]
f[n-siz[y]]
f[n−siz[y]] 加 1,统计完所有点的子树后将得到所有的
f
[
i
]
f[i]
f[i] ,那么答案数列的生成函数就是
G
(
x
)
=
∑
i
=
1
n
f
[
i
]
(
1
+
x
)
i
G(x)=\sum_{i=1}^{n} f[i](1+x)^i
G(x)=i=1∑nf[i](1+x)i
如果我们令函数 F ( x ) = ∑ i = 1 n f [ i ] x i F(x)=\sum_{i=1}^{n}f[i]x^i F(x)=∑i=1nf[i]xi ,那么就要求函数 G ( x ) = F ( x + 1 ) G(x)=F(x+1) G(x)=F(x+1)
怎么做呢?安排 n n n 个横坐标对 F ( x ) F(x) F(x) 多点求值再横坐标减 1 对 G ( x ) G(x) G(x) 快速插值……时间复杂度 O ( n log 2 n ) O(n\log^2 n) O(nlog2n) 常数🤮
其实我们可以分治来做。
若我们已经求出
F
0
=
∑
i
=
1
m
i
d
f
[
i
]
(
x
+
1
)
i
,
F
1
=
∑
i
=
m
i
d
+
1
n
f
[
i
]
(
1
+
x
)
i
−
m
i
d
F_0=\sum_{i=1}^{mid}f[i](x+1)^{i}~,~F_1=\sum_{i=mid+1}^{n} f[i](1+x)^{i-mid}
F0=i=1∑midf[i](x+1)i , F1=i=mid+1∑nf[i](1+x)i−mid
那么可以通过一次多项式乘法,一次多项式加法求出
F
=
F
0
+
F
1
⋅
(
1
+
x
)
m
i
d
F=F_0+F_1\cdot(1+x)^{mid}
F=F0+F1⋅(1+x)mid
由于 F 0 , F 1 , ( 1 + x ) m i d F_0,F_1,(1+x)^{mid} F0,F1,(1+x)mid 的次数都是 n 2 \frac{n}{2} 2n 级别的,所以复杂度正确常熟优秀, O ( n log 2 n ) O(n\log^2n) O(nlog2n) 。
另:不会真有人傻到预处理每个
(
1
+
x
)
m
i
d
(1+x)^{mid}
(1+x)mid 存到 vector
中吧……其实
(
1
+
x
)
n
=
∑
i
=
0
n
(
n
i
)
x
i
(1+x)^n=\sum_{i=0}^{n}{n\choose i}x^i
(1+x)n=∑i=0n(in)xi ,完全可以在多项式乘法之前当场给出来。
F
0
,
F
1
F_0,F_1
F0,F1 也可以通过指针直接存在一个大数组里,因为我们时刻需要的位置最多
O
(
n
)
O(n)
O(n) 。
好吧我是废物
∑
i
=
0
n
f
[
i
]
(
1
+
x
)
i
=
∑
i
=
0
n
f
[
i
]
∑
j
=
0
i
(
i
j
)
x
j
=
∑
i
=
0
n
f
[
i
]
i
!
∑
j
=
0
i
1
(
i
−
j
)
!
x
j
1
j
!
=
∑
j
=
0
n
x
j
1
j
!
∑
i
=
j
n
f
[
i
]
i
!
1
(
i
−
j
)
!
\sum_{i=0}^nf[i](1+x)^i=\sum_{i=0}^nf[i]\sum_{j=0}^i{i\choose j}x^j=\sum_{i=0}^n f[i]i!\sum_{j=0}^i\frac{1}{(i-j)!}x^j\frac{1}{j!}\\ =\sum_{j=0}^nx^j\frac{1}{j!}\sum_{i=j}^n f[i]i!\frac{1}{(i-j)!}
i=0∑nf[i](1+x)i=i=0∑nf[i]j=0∑i(ji)xj=i=0∑nf[i]i!j=0∑i(i−j)!1xjj!1=j=0∑nxjj!1i=j∑nf[i]i!(i−j)!1
直接卷积完事, O ( n log n ) O(n\log n) O(nlogn) 。
CODE
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<random>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
int xchar() {
static const int maxn = 1000000;
static char b[maxn];
static int pos = 0,len = 0;
if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
if(pos == len) return -1;
return b[pos ++];
}
//#define getchar() xchar()
LL read() {
LL f = 1,x = 0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}
const int MOD = 924844033;
const int RM = 5;
int n,m,s,o,k;
int qkpow(int a,int b) {
int res = 1;
while(b > 0) {
if(b & 1) res = res *1ll* a % MOD;
a = a *1ll* a % MOD; b >>= 1;
}return res;
}
int om,xm[MAXN<<2],rev[MAXN<<2];
void NTT(int *s,int n,int op) {
for(int i = 1;i < n;i ++) {
rev[i] = (rev[i>>1]>>1) | ((i&1) ? (n>>1):0);
if(rev[i] < i) swap(s[rev[i]],s[i]);
}
om = qkpow(RM,(MOD-1)/n); xm[0] = 1;
if(op < 0) om = qkpow(om,MOD-2);
for(int i = 1;i <= n;i ++) xm[i] = xm[i-1] *1ll* om % MOD;
for(int k = 2,t = n>>1;k <= n;k <<= 1,t >>= 1) {
for(int j = 0;j < n;j += k) {
for(int i = j,l = 0;i < j+(k>>1);i ++,l += t) {
int A = s[i],B = s[i+(k>>1)];
s[i] = (A + xm[l]*1ll*B) % MOD;
s[i+(k>>1)] = (A+MOD-xm[l]*1ll*B%MOD)%MOD;
}
}
}
if(op < 0) {
int iv = qkpow(n,MOD-2);
for(int i = 0;i < n;i ++) s[i] = s[i] *1ll* iv % MOD;
}return ;
}
int fac[MAXN],inv[MAXN],invf[MAXN];
int C(int n,int m) {
if(m < 0 || m > n) return 0;
return fac[n] *1ll* invf[n-m] % MOD *1ll* invf[m] % MOD;
}
int hd[MAXN],nx[MAXN<<1],v[MAXN<<1],cne;
void ins(int x,int y) {
nx[++ cne] = hd[x]; v[cne] = y; hd[x] = cne;
}
int ans[MAXN];
int siz[MAXN],ct[MAXN];
void dfs(int x,int ff) {
siz[x] = 1;
for(int i = hd[x];i;i = nx[i]) {
if(v[i] != ff) {
dfs(v[i],x);
ct[siz[v[i]]] ++;
siz[x] += siz[v[i]];
}
}
ct[n-siz[x]] ++;
return ;
}
vector<int> g[MAXN<<2];
int h[MAXN<<3];
int a_[MAXN<<2],b_[MAXN<<2];
void solve(int *f,int l,int r) {
if(l == r) {
f[0] = f[1] = ct[l];
return ;
}
int md = (l + r) >> 1,l1 = md-l+1,l2 = r-md;
solve(f,l,md); solve(f+l1+1,md+1,r);
for(int i = 0;i <= l1;i ++) a_[i] = C(l1,i);
for(int i = 0;i <= l2;i ++) b_[i] = f[l1+1+i];
int le = 1; while(le <= r-l+1) le <<= 1;
NTT(a_,le,1); NTT(b_,le,1);
for(int i = 0;i < le;i ++) a_[i] = a_[i] *1ll* b_[i] % MOD;
NTT(a_,le,-1);
for(int i = 0;i < le;i ++) {
if(i <= l1) f[i] = (f[i]+a_[i]) % MOD;
else if(i <= r-l+1) f[i] = a_[i];
else f[i] = 0;
a_[i] = b_[i] = 0;
}return ;
}
int main() {
n = read();
fac[0]=fac[1]=inv[0]=inv[1]=invf[0]=invf[1]=1;
for(int i = 2;i <= n;i ++) {
fac[i] = fac[i-1] *1ll* i % MOD;
inv[i] = (MOD-inv[MOD%i]) *1ll* (MOD/i) % MOD;
invf[i] = invf[i-1] *1ll* inv[i] % MOD;
}
for(int i = 1;i < n;i ++) {
s = read();o = read();
ins(s,o); ins(o,s);
}
dfs(1,0);
for(int i = 1;i <= n;i ++) {
ans[i] = C(n,i) *1ll* n % MOD;
}
solve(h,1,n);
for(int i = 1;i <= n;i ++) {
(ans[i] += MOD-h[i]) %= MOD;
AIput(ans[i],'\n');
}
return 0;
}