LuoguP4002 生成树计数
分析
式子不会推,黑科技也不懂,退役吧。。。
第一个显然的转化是
A
n
s
=
∑
T
∏
a
i
d
i
d
i
m
∑
d
i
m
Ans=\sum_T\prod a_i^{d_i}d_i^m\sum d_i^m
Ans=∑T∏aididim∑dim
将每个点的度数映射到purfer序列上,得到
A
n
s
=
(
n
−
2
)
!
∏
d
i
!
∏
a
i
d
i
+
1
⋅
(
d
i
+
1
)
m
∑
(
d
i
+
1
)
m
Ans=\frac{(n-2)!}{\prod d_i!}\prod a_i^{d_i+1}\cdot(d_i+1)^m\sum (d_i+1)^m
Ans=∏di!(n−2)!∏aidi+1⋅(di+1)m∑(di+1)m
把那个
∑
\sum
∑提出来,相当于是每次对某个
d
i
+
1
d_i+1
di+1的指数增加
m
m
m,枚举增加的这个指数,得到
A
n
s
=
(
n
−
2
)
!
∏
a
i
∑
j
(
∏
j
≠
i
(
d
i
+
1
)
m
d
i
!
a
i
d
i
)
(
d
j
+
1
)
2
m
d
j
!
Ans=(n-2)!\prod a_i \sum_j(\prod_{j \neq i} \frac{(d_i+1)^m}{d_i!}a_i^{d_i} )\frac{(d_j+1)^{2m}}{d_j!}
Ans=(n−2)!∏ai∑j(∏j̸=idi!(di+1)maidi)dj!(dj+1)2m
推到这里,已经有一些眉目了,前面的
(
n
−
2
)
!
∏
a
i
(n-2)!\prod a_i
(n−2)!∏ai是常数。考虑对后面的
∑
\sum
∑采用生成函数。
A
(
x
)
=
(
i
+
1
)
m
i
!
x
i
A(x)=\frac{(i+1)^m}{i!}x^i
A(x)=i!(i+1)mxi
B
(
x
)
=
(
i
+
1
)
2
m
i
!
x
i
B(x)=\frac{(i+1)^{2m}}{i!}x^i
B(x)=i!(i+1)2mxi
那么实际上,
A
n
s
Ans
Ans的生成函数就是
A
A
A和
B
B
B卷积的结果。
F
=
∑
j
B
(
a
j
x
)
∏
j
≠
i
A
(
a
i
x
)
=
(
∑
j
B
(
a
j
x
)
A
(
a
j
x
)
)
(
e
x
p
∑
i
l
n
A
(
a
i
x
)
)
F=\sum_j B(a_jx)\prod_{j\neq i}A(a_ix)=(\sum_j \frac{B(a_jx)}{A(a_jx)})(exp^{\sum_ilnA(a_ix)})
F=∑jB(ajx)∏j̸=iA(aix)=(∑jA(ajx)B(ajx))(exp∑ilnA(aix))
如果不考虑
a
i
a_i
ai的影响,接下来就很套路了。
考虑
a
i
a_i
ai之后,把
a
i
a_i
ai带入
∑
j
B
(
a
j
x
)
A
(
a
j
x
)
\sum_j\frac{B(a_jx)}{A(a_jx)}
∑jA(ajx)B(ajx),
e
x
p
∑
i
l
n
A
(
a
i
x
)
exp^{\sum_ilnA(a_ix)}
exp∑ilnA(aix)求和之后,得到
t
t
t次方的系数要乘上
∑
a
i
t
\sum a_i^t
∑ait
这个东西的处理也是套路。。
k次方求和
考虑
F
(
x
)
=
∑
x
t
∑
a
i
t
=
∑
1
1
−
a
i
x
F(x)=\sum x^t\sum a_i^t=\sum\frac{1}{1-a_ix}
F(x)=∑xt∑ait=∑1−aix1
发现
l
n
′
(
1
−
a
i
x
)
=
−
a
i
1
−
a
i
x
ln'(1-a_ix)=\frac{-a_i}{1-a_ix}
ln′(1−aix)=1−aix−ai
考虑先计算
G
(
x
)
=
−
∑
x
=
0
k
x
t
∑
i
=
0
n
a
i
t
+
1
=
∑
l
n
′
(
1
−
a
i
x
)
=
l
n
′
(
∏
1
−
a
i
x
)
G(x)=-\sum_{x=0}^k x^t\sum_{i=0}^n a_i^{t+1}=\sum ln'(1-a_ix)=ln'(\prod 1-a_ix)
G(x)=−∑x=0kxt∑i=0nait+1=∑ln′(1−aix)=ln′(∏1−aix)
对于
(
∏
1
−
a
i
x
)
(\prod 1-a_ix)
(∏1−aix)用分治卷积可以做到
O
(
n
l
o
g
2
)
O(nlog^2)
O(nlog2)
然后再多项式求ln再求导就行了。
然后
F
(
x
)
=
−
x
G
(
x
)
+
n
F(x)=-xG(x)+n
F(x)=−xG(x)+n
搞定!
代码
~~(找个标称抄一抄得了)~~各种板子叠一叠就。。。行了。。。。
#include<bits/stdc++.h>
#define pb push_back
const int N = 1e5 + 10, P = 998244353;
typedef std::vector<int> VI;
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int A[N], B[N], C[N], R[N], w[N], InvL, a[N], ta[N], tb[N], tc[N], fac[N], ivf[N], sum[N], L, n, m;
int fix(int x) {return (x >> 31 & P) + x;}
int add(int a, int b) {return a += b, a >= P ? a - P : a;}
int mul(int a, int b) {return 1LL * a * b % P;}
int Pow(int x, int k) {
int r = 1;
for(;k; x = mul(x, x), k >>= 1)
if(k & 1)
r = mul(r, x);
return r;
}
int Inv(int x) {return Pow(x, P - 2);}
void Pre(int m) {
int x = 0; L = 1;
for(;(L <<= 1) < m; ++x) ;
for(int i = 1;i < L; ++i)
R[i] = R[i >> 1] >> 1 | (i & 1) << x;
int wn = Pow(3, (P - 1) / L); w[0] = 1;
for(int i = 1;i < L; ++i)
w[i] = mul(w[i - 1], wn);
InvL = Inv(L);
}
void DFT(int *F) {
for(int i = 0;i < L; ++i)
if(i < R[i])
std::swap(F[i], F[R[i]]);
for(int i = 1, d = L >> 1; i < L; i <<= 1, d >>= 1)
for(int j = 0;j < L; j += i << 1) {
int *l = F + j, *r = F + j + i, *p = w, tp;
for(int k = i;k--; ++l, ++r, p += d)
tp = mul(*r, *p), *r = fix(*l - tp), *l = add(*l, tp);
}
}
void Mul(int *A, int *B, int *C, int m) {
Pre(m << 1);
for(int i = m;i <= L; ++i)
A[i] = B[i] = 0;
DFT(A); DFT(B);
for(int i = 0;i < L; ++i)
C[i] = mul(A[i], B[i]);
DFT(C);
std::reverse(C + 1, C + L);
for(int i = 0;i < L; ++i)
C[i] = mul(C[i], InvL);
}
VI Div(int L, int R) {
if(L == R) {
VI vec;
vec.pb(1); vec.pb(fix(-a[L]));
return vec;
}
int m = L + R >> 1;
VI vl = Div(L, m), vr = Div(m + 1, R);
Pre(R - L + 1);
for(int i = 0;i < ::L; ++i) {
ta[i] = tb[i] = 0;
if(i <= m - L + 1) ta[i] = vl[i];
if(i <= R - m) tb[i] = vr[i];
}
Mul(ta, tb, ta, R - L + 1);
VI res;
for(int i = 0;i <= R - L + 1; ++i)
res.pb(ta[i]);
return res;
}
void Inv(const int A[], int *B, int n) {
static int C[N], D[N];
B[0] = Inv(A[0]); int m = 2;
for(; m >> 1 < n; m <<= 1) {
Pre(m << 1);
for(int i = 0;i < m; ++i)
C[i] = A[i], C[i + m] = 0;
for(int i = 0;i < m >> 1; ++i)
D[i] = B[i];
for(int i = m >> 1;i < m << 1; ++i)
D[i] = 0;
DFT(C); DFT(D);
for(int i = 0;i < L; ++i)
C[i] = mul(fix(2 - mul(C[i], D[i])), D[i]);
DFT(C);
for(int i = 0;i < m; ++i)
B[i] = mul(C[L - i & L - 1], InvL);
}
}
void Deri(int *A, int *B, int m) {
for(int i = 0;i < m - 1; ++i)
B[i] = mul(A[i + 1], i + 1);
B[m] = 0;
}
void Inte(int *A, int m) {
for(int i = m - 1;i; --i)
A[i] = mul(A[i - 1], Inv(i));
A[0] = 0;
}
void Ln(int *B, int *A, int m) {
static int dA[N], G[N];
for(int i = 0;i < m; ++i)
A[i] = B[i];
Deri(A, dA, m);
Inv(A, G, m);
Mul(dA, G, G, m);
Inte(G, m);
for(int i = 0;i < m; ++i)
A[i] = G[i];
}
void Exp(int *A, int *B, int n) {
static int C[N], D[N];
B[0] = 1; int m = 2;
for(;m >> 1 <= n; m <<= 1) {
for(int i = 0;i < m >> 1; ++i)
C[i] = D[i] = B[i];
for(int i = m >> 1; i < m << 1; ++i)
C[i] = D[i] = 0;
Ln(C, C, m);
for(int i = 0;i < m; ++i)
C[i] = fix(A[i] - C[i]);
C[0] = add(C[0], 1);
Mul(C, D, C, m);
for(int i = 0;i < m; ++i)
B[i] = C[i];
}
}
int main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n = ri(); m = ri();
if(n == 1) return puts("1"), 0;
fac[0] = 1; for(int i = 1;i <= n; ++i) fac[i] = mul(fac[i - 1], i);
ivf[n] = Pow(fac[n], P - 2); for(int i = n; i; --i) ivf[i - 1] = mul(ivf[i], i);
for(int i = 1;i <= n; ++i) a[i] = ri();
VI vec = Div(1, n);
for(int i = 0;i <= n; ++i)
tc[i] = vec[i];
int Len = 1; for(;Len <= n;) Len <<= 1;
Ln(tc, sum, Len);
for(int i = 1;i <= n; ++i)
sum[i] = fix(-mul(sum[i], i));
sum[0] = n;
for(int i = 0; i < n; ++i) {
A[i] = mul(Pow(i + 1, m), ivf[i]);
B[i] = mul(Pow(i + 1, m << 1), ivf[i]);
}
Ln(A, tc, Len); Inv(A, C, Len);
Mul(B, C, B, Len << 1);
for(int i = 0;i < n; ++i) {
B[i] = mul(B[i], sum[i]);
A[i] = mul(tc[i], sum[i]);
}
for(int i = n; i < Len << 1; ++i) B[i] = 0;
Exp(A, C, Len);
Mul(B, C, B, Len << 1);
int res = mul(B[n - 2], fac[n - 2]);
for(int i = 1;i <= n; ++i)
res = mul(res, a[i]);
printf("%d\n", res);
return 0;
}