luoguP4389 付公主的背包 多项式求逆 多项式求ln 多项式求exp 生成函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvzelong2014/article/details/85336559

luoguP4389 付公主的背包

题目传送门

分析

神仙题系列。。。
首先写出每件商品的生成函数,假设体积为 V V
A ( x ) = i = 0 x i v = 1 1 x v A(x)=\sum_{i=0}^{\infty}x^{iv}=\frac{1}{1-x^{v}}
答案就是
A n s ( x ) 1 1 x v i ( m o d x m + 1 ) Ans(x)\equiv\prod\frac{1}{1-x^{vi}}(mod x^{m+1})
裸跑 N T T NTT 就是 O ( n m l o g ) O(nmlog)
乘积的处理比较麻烦,尝试转化成加和,两边同时取对数
l n ( A n s ( x ) ) l n ( 1 1 x v i ) ( m o d x m + 1 ) ln(Ans(x))\equiv\sum ln(\frac{1}{1-x^{v_i}})(mod x^{m+1})
尝试把 l n ( 1 1 x v i ) ln(\frac{1}{1-x^{v_i}}) 泰勒展开,既然是对多项式求 l n ln ,肯定是先求导后积分。
l n ( 1 1 x v ) = l n ( 1 x v ) = ( v x v 1 ) ( 1 1 x v ) = v i = 0 x v ( i + 1 ) 1 = i = 1 v x v i 1 ln'(\frac{1}{1-x^{v}})=-ln'(1-x^v)=-(-vx^{v-1})\cdot(\frac{1}{1-x^v})=v\sum_{i= 0}^{\infty}x^{v(i+1)-1}=\sum_{i= 1}^{\infty}vx^{vi-1}
积分回去之后发现是
l n ( 1 1 x v ) = i = 1 x v i i \int ln'(\frac{1}{1-x^{v}})= \sum_{i= 1}^{\infty}\frac{x^{vi}}{i}
非常漂亮的一个式子。
注意到我们仅仅需要考虑 m m 以内的 x x
而上面的式子可以采用调和级数求和。
于是我们只需要在 O ( m l o g m ) O(mlogm) 的时间内就可以求出 l n ( A n s ( x ) ) ln(Ans(x))
然后多项式exp即可。

多项式exp

还是一样的分治思想
f ( x ) = e A ( x ) f(x)=e^{A(x)}
l n ( f ( x ) ) A ( x ) = 0 ln(f(x))-A(x)=0
g ( f ( x ) ) = l n ( f ( x ) ) A ( x ) g(f(x))=ln(f(x))-A(x)
假设我们已经求了
f 0 ( x ) e A ( x ) ( m o d    x n ) f_0(x)\equiv e^{A(x)}(\mod x^{n})
希望求
f ( x ) e A ( x ) ( m o d    x 2 n ) f(x)\equiv e^{A(x)}(\mod x^{2n})
那么
g ( f ( x ) ) 0 ( m o d    x 2 n ) g(f(x))\equiv0(\mod x^{2n})
考虑在 f 0 f_0 处泰勒展开
g ( f ( x ) ) g ( f 0 ( x ) ) + g ( f 0 ( x ) ) ( f ( x ) f 0 ( x ) ) + g ( f ( x ) ) 2 ( f ( x ) f 0 ( x ) ) 2 ( m o d    x 2 n ) g(f(x))\equiv g(f_0(x)) + g'(f_0(x))(f(x)-f_0(x))+\frac{g''(f(x))}{2}(f(x)-f_0(x))^2 \cdots(\mod x^{2n})
注意到
f ( x ) f 0 ( x ) ( m o d    x n ) f(x)\equiv f_0(x)(\mod x^n)
所以
f ( x ) f 0 ( x ) 0 ( m o d    x n ) f(x)-f_0(x)\equiv 0(\mod x^n)
这就意味着, f ( x ) f ( x 0 ) f(x)-f(x_0) m o d    x 2 n \mod x^{2n} 意义下的最低幂次不小于 x n x^n
所以平方之后的最低幂次不小于 x 2 n x^{2n} ,在 m o d    x 2 n \mod x^{2n} 意义下为 0 0
所以
g ( f ( x ) ) g ( f 0 ( x ) ) + g ( f 0 ( x ) ) ( f ( x ) f 0 ( x ) ) ( m o d    x 2 n ) 0 g(f(x))\equiv g(f_0(x)) + g'(f_0(x))(f(x)-f_0(x))(\mod x^{2n})\equiv 0
f ( x ) f 0 ( x ) g ( f 0 ( x ) ) g ( f 0 ( x ) ) ( m o d    x 2 n ) f(x)\equiv f_0(x)-\frac{g(f_0(x))}{g'(f_0(x))}(\mod x^{2n})
g ( f 0 ( x ) ) = 1 f 0 ( x ) g'(f_0(x))=\frac{1}{f_0(x)} 代入
f ( x ) f 0 ( x ) ( 1 l n ( f 0 ( x ) ) + A ( x ) ) ( m o d    x 2 n ) f(x)\equiv f_0(x)(1-ln(f_0(x))+A(x))(\mod x^{2n})
分治+多项式求ln+NTT即可。
复杂度 T ( n ) = T ( n 2 ) + O ( n l o g n ) = T ( n l o g n ) T(n)=T(\frac{n}{2})+O(nlogn)=T(nlogn)

代码

#include<bits/stdc++.h>
const int N = 262144, M = 1e7 + 10, P = 1004535809;
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 w[N], R[N], A[N], B[N], sz[N], f[M], g[M], v[N], tp, L, InvL, n;
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) {
	L = 1; int x = 0;
	for(;(L <<= 1) < m; ++x) ;
	for(int i = 1;i < L; ++i)
		R[i] = R[i >> 1] >> 1 | (i & 1) << x;
	w[0] = 1; int wn = Pow(3, (P - 1) / L);
	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);
		}
}
int C(int m, int n) {return mul(mul(f[m], g[n]), g[m - n]);}
void Get(int n) {
	f[0] = 1; for(int i = 1;i <= n; ++i) f[i] = mul(f[i - 1], i);
	g[n] = Inv(f[n]); for(int i = n;i; --i) g[i - 1] = mul(g[i], i);
}
int main() {
	int n = ri(), m = ri(), s = ri(), lim = std::min(n / s, m);
	for(int i = 0;i <= m; ++i) v[i] = ri();
	Get(std::max(n, m));
	for(int i = 0;i <= lim; ++i) {
		int cnt = i * s;
		A[i] = mul(mul(C(m, i), C(n, cnt)), mul(f[cnt], Pow(g[s], i)));
		A[i] = mul(A[i], mul(Pow(m - i, n - cnt), f[i]));
	}
	for(int i = 0;i <= lim; ++i)
		B[lim - i] = i & 1 ? fix(-g[i]) : g[i];
	Pre((lim << 1) + 1);
	DFT(A); DFT(B);
	for(int i = 0;i < L; ++i)
		A[i] = mul(A[i], B[i]);
	DFT(A);
	int ans = 0;
	for(int i = 0;i <= lim; ++i) {
		ans = add(ans, mul(mul(v[i], g[i]), mul(A[L - i - lim & L - 1], InvL)));
	}
	printf("%d\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/85336559
今日推荐