zl程序教程

您现在的位置是:首页 >  其它

当前栏目

【YBT2022寒假Day6 A】【luogu CF891E】随机减法 / Lust(EGF)

随机 Luogu 减法 寒假 Day6
2023-09-27 14:28:27 时间

随机减法 / Lust

题目链接:YBT2022寒假Day6 A / luogu CF891E

题目大意

给你一个数组,每次随机选一个数减一,然后贡献增加除了这个数以外所有数的乘积,然后问你操作 k 次之后期望的贡献和。

思路

它这个除了以外某个数以外的乘积很不好搞,我们考虑一定把它弄成跟全部乘积有关的。
然后你发现每次减一,那全部乘积就减少了除了这个数以外所有数的乘积。

那每次的贡献就是全部乘积的减小量,那总贡献就是全部乘积总共减少的量,也就是: ∏ a i − ∏ ( a i − b i ) \prod a_i-\prod(a_i-b_i) ai(aibi) b i b_i bi k k k 次操作选了 a i a_i ai 多少次)
然后 b i b_i bi 是每个的次数,你还要放的顺序,所以要乘上 k ! ∏ b i ! \dfrac{k!}{\prod b_i!} bi!k!

然后因为是期望,所以要乘概率: 1 n k \dfrac{1}{n^k} nk1
所以我们要得到的就是: ∏ a i − ∑ b 1 n k k ! ∏ b i ! ∏ ( a i − b i ) \prod a_i-\sum\limits_{b}\dfrac{1}{n^k}\dfrac{k!}{\prod b_i!}\prod(a_i-b_i) aibnk1bi!k!(aibi)

然后把 b b b 的放在一起: k ! n k ∏ a i − b i b i ! \dfrac{k!}{n^k}\prod\dfrac{a_i-b_i}{b_i!} nkk!bi!aibi
你发现右边这个 ∏ \prod 里面的好像是个 EGF 的性质,考虑试试:

f ( i ) = ∑ j = 0 a i − j j ! x j f(i)=\sum\limits_{j=0}\dfrac{a_i-j}{j!}x^j f(i)=j=0j!aijxj
f ( i ) = ∑ j = 0 ( a i j ! x j − x ( j − 1 ) ! x j − 1 ) f(i)=\sum\limits_{j=0}(\dfrac{a_i}{j!}x^j-\dfrac{x}{(j-1)!}x^{j-1}) f(i)=j=0(j!aixj(j1)!xxj1)
f ( i ) = ∑ j = 0 a i − x j ! x j = ( a i − x ) e x f(i)=\sum\limits_{j=0}\dfrac{a_i-x}{j!}x^j=(a_i-x)e^x f(i)=j=0j!aixxj=(aix)ex

然后你是要每一项乘起来:
F ( x ) = ∏ i = 1 n f ( i ) = e n x ∏ i = 1 n ( a i − x ) F(x)=\prod\limits_{i=1}^nf(i)=e^{nx}\prod\limits_{i=1}^n(a_i-x) F(x)=i=1nf(i)=enxi=1n(aix)
F ( x ) = ∑ i = 0 n i x i i ! ∏ i = 1 n ( a i − x ) F(x)=\sum\limits_{i=0}n^i\dfrac{x^i}{i!}\prod\limits_{i=1}^n(a_i-x) F(x)=i=0nii!xii=1n(aix)

那么可以看出 ∏ i = 1 n ( a i − x ) \prod\limits_{i=1}^n(a_i-x) i=1n(aix) 是一个多项式,而且暴力算的复杂度是 O ( n 2 ) O(n^2) O(n2),是可以的。
那么假设我们得出来的结果是: ∑ c i x i \sum\limits c_ix^i cixi
F ( x ) = ∑ i = 0 n i x i i ! ∑ i = 0 c i x i F(x)=\sum\limits_{i=0}n^i\dfrac{x^i}{i!}\sum\limits_{i=0}c_ix^i F(x)=i=0nii!xii=0cixi

那我们答案要的自然是第 k k k 项:
[ x k ] F ( x ) = ∑ i = 0 k n k − i x k − i ( k − i ) ! c i x i = ∑ i = 0 k n k − i c i ( k − i ) ! x k [x^k]F(x)=\sum\limits_{i=0}^k n^{k-i}\dfrac{x^{k-i}}{(k-i)!}c_{i}x^{i}=\sum\limits_{i=0}^k\dfrac{n^{k-i}c_i}{(k-i)!}x^k [xk]F(x)=i=0knki(ki)!xkicixi=i=0k(ki)!nkicixk

然后我们带回去:
E = k ! n k ∗ [ x k ] F ( x ) E=\dfrac{k!}{n^k}*[x^k]F(x) E=nkk![xk]F(x)
= ∑ i = 0 k k ! n k n k − i c i ( k − i ) ! x k =\sum\limits_{i=0}^k\dfrac{k!}{n^k}\dfrac{n^{k-i}c_i}{(k-i)!}x^k =i=0knkk!(ki)!nkicixk
= ∑ i = 0 k k ! c i n i ( k − i ) ! =\sum\limits_{i=0}^k\dfrac{k!c_i}{n^i(k-i)!} =i=0kni(ki)!k!ci
= ∑ i = 0 k ( k − i + 1 ) ( k − i + 2 ) ( . . . ) ( k ) c i n i =\sum\limits_{i=0}^k\dfrac{(k-i+1)(k-i+2)(...)(k)c_i}{n^i} =i=0kni(ki+1)(ki+2)(...)(k)ci
(不能直接算阶乘,所以要拆开来抵消,每次在原来基础上乘新的数)

然后最后 ∏ a i − E \prod a_i-E aiE 即可。

代码

#include<cstdio>
#define ll long long
#define mo 1000000007

using namespace std;

ll n, k, a[5001], sum, c[5001], cc[5001];

void get_C() {
	c[0] = 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++)
			cc[j] = c[j - 1];
		for (int j = 0; j <= n; j++)
			c[j] = (c[j] * a[i] % mo - cc[j] + mo) % mo;
	}
}

ll ksm(ll x, ll y) {
	ll re = 1;
	while (y) {
		if (y & 1) re = re * x % mo;
		x = x * x % mo;
		y >>= 1;
	}
	return re;
}

int main() {
//	freopen("calculate.in", "r", stdin);
//	freopen("calculate.out", "w", stdout);
	
	scanf("%lld %lld", &n, &k); sum = 1;
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]); sum = sum * a[i] % mo;
	}
	
	get_C();
	
	ll xnfn = 0, tmp = 1, invn = ksm(n, mo - 2);
	for (int i = 0; i <= n; i++) {
		(xnfn += c[i] * tmp % mo) %= mo;
		(tmp *= invn * (k - i) % mo) %= mo;
	}
	printf("%lld", (sum - xnfn + mo) % mo);
	
	return 0;
}