LuoguP4002 生成树计数 多项式exp多项式ln多项式求逆 分治+NTT

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=Taididimdim
将每个点的度数映射到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!(n2)!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=(n2)!aij(j̸=idi!(di+1)maidi)dj!(dj+1)2m
推到这里,已经有一些眉目了,前面的 ( n − 2 ) ! ∏ a i (n-2)!\prod a_i (n2)!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))(expilnA(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)} expilnA(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)=xtait=1aix1
发现 l n ′ ( 1 − a i x ) = − a i 1 − a i x ln'(1-a_ix)=\frac{-a_i}{1-a_ix} ln(1aix)=1aixai
考虑先计算
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=0kxti=0nait+1=ln(1aix)=ln(1aix)
对于 ( ∏ 1 − a i x ) (\prod 1-a_ix) (1aix)用分治卷积可以做到 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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值