CF891E: Lust 题解(指数生成函数)

E:

题意:给你序列 \(a\),进行 \(k\) 次操作,每次随机选择一个 \(x\),使得 \(s+=\prod\limits_{i=1}^na_i*(i!=x)\)\(a_i-=1\),求 \(k\) 次后 \(s\) 期望值。(n<=5000, k<=1e9)


Solution:

首先转化下题意,我们把序列 a 看做是一个 n 维的超立方体,每次的操作相当于随机选择一维,切下来一个厚度为1的面包片(比喻),s 加上的值就是面包片的体积,\(a_i\) 减去 1 相当于这一维的厚度减少了 1 ,因为我们把面包片拿走了。那么就很好推出:\(s = \prod\limits_{i=1}^na_i-\prod\limits_{i=1}^n(a_i-b_i)\)\(b_i\) 为第 i 个位置被选择的次数。

前一项是初始体积,我们求一下切 k 次后的期望体积 \(E=\prod\limits_{i=1}^n(a_i-b_i)\) 。隐约感觉出这题是生成函数,因此我们推式子时尽量往那里靠。

我们一共有 \(n^k\) 种随机操作方式,发现每一种不同的 b 数列对应一种不同的贡献,设 \(f(b_1,b_2,...,b_n)\) 表示 b 数列这样分布的次数,其中 \(\sum b_i=k\)

由排列组合的知识可知 \(f(b_1,b_2,...,b_n)=\frac{k!}{b_1!b_2!...b_n!}\)

每一种 b 数列的贡献是 \(\prod\limits_{i=1}^n(a_i-b_i)\),则: \(E=\frac{1}{n^k}\sum\limits_Bf(b_1,b_2,...,b_n)\prod\limits_{i=1}^n(a_i-b_i)\)。(\(\sum\limits_B\) 是指把所有 b 数列情况加起来)

想求这个式子,就需要搬出我们的指数生成函数 (EGF)。

因为 \(a_i-b_i\) 是连乘的形式,我们可以放在指数生成函数中系数的位置上,表示选择每个 \(b_i\) 值造成的贡献。

\(F(x)_i\) 表示第 i 个位置的生成函数:

\(F(x)_i=(a_i-0)+(a_i-1)\frac{x^1}{1!}+(a_i-2)\frac{x^2}{2!}+...+(a_i-n)\frac{x^n}{n!}\)

\(x^k\) 的系数相当于 \(b_i=k\) 时的贡献。

\(F(x)_i=\sum\limits_{j=0}^n(a_i-j)\frac{x^j}{j!}\)

\(F(x)_i=\sum\limits_{j=0}^n(a_i\frac{x^j}{j!}-\frac{x^{j-1}}{(j-1)!}·x)\)

\(F(x)_i=\sum\limits_{j=0}^na_i\frac{x^j}{j!}-\sum\limits_{j=1}^{n}\frac{x^{j-1}}{(j-1)!}·x\)

\(F(x)_i=\sum\limits_{j=0}^na_i\frac{x^j}{j!}-\sum\limits_{j=0}^{n}\frac{x^j}{j!}·x\)

\(F(x)_i=\sum\limits_{j=0}^n(a_i-x)\frac{x^j}{j!}\)

\(F(x)_i=(a_i-x)e^x\)

总生成函数:\(F(x)=\prod\limits_{i=1}^nF(x)_i=e^{nx}\prod\limits_{i=1}^n(a_i-x)\),这个式子助于我们计算。

\(p_i\) 为多项式 \(\prod\limits_{i=1}^n(a_i-x)\) 的系数,我们知道 \(e^{nx}=\sum\limits_{i=0}^\infty n^i\frac{x^i}{i!}\),所以 \(F(x)\)\(x^k\) 项为: \([x^k]F(x)=\sum\limits_{i=0}^kp_i\frac{n^{k-i}}{(k-i)!}\)

同时,表示 \(F(x)\) 意义的式子为: \(F(x)=\sum\limits_{k=0}^\infty(\sum\limits_B\frac{1}{b_1!b_2!...b_n!}\prod\limits_{i=1}^n(a_i-b_i))x^k\)

我们要求的期望为:

\(E=\frac{1}{n^k}\sum\limits_Bf(b_1,b_2,...,b_n)\prod\limits_{i=1}^n(a_i-b_i)\)

\(E=\frac{1}{n^k}\sum\limits_B\frac{k!}{b_1!b_2!...b_n!}\prod\limits_{i=1}^n(a_i-b_i)\)

发现就是 \(F(x)\)\(x^k\) 项系数乘上常数 \(\frac{k!}{n^k}\)

\(E=[x^k]F(x)·\frac{k!}{n^k}\)

\(E=\sum\limits_{i=0}^kp_i\frac{n^{k-i}}{(k-i)!}·\frac{k!}{n^k}\)

\(E=\sum\limits_{i=0}^kp_i\frac{k^{\underline{i}}}{n^i}\)

\(k\) 太大,还是不会求?其实 \(p_i\) 只有 \(n\) 项,后面的项全是 0。(如果你推 \(F(x)\) 系数时反了过来:\(\sum\limits_{i=0}^kp^{k-i}\frac{n^i}{i!}\),那么你应该注意到 \(i>k-n\) 时才有意义)

所以最终答案为 \(s=\prod\limits_{i=1}^na_i-\sum\limits_{i=0}^np_i\frac{k^{\underline{i}}}{n^i}\)

计算多项式 \(\prod\limits_{i=1}^n(a_i-x)\) 可以用多项式分治乘,从 \(n^2\) 优化至 \(nlog^2n\),但是这题模数不是998244353,FFT又怕掉精度,所以直接写暴力了。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define FOR() ll le=e[u].size();for(ll i=0;i<le;i++)
#define QWQ cout<<"QwQ\n";
#define ll long long
#include <complex>
#include <queue>
#include <map>
#define ls now<<1
#define rs now<<1|1

using namespace std;
const ll N=501010;
const ll qwq=303030;
const ll inf=0x3f3f3f3f;
const ll p=1000000007;

inline ll read() {
    ll sum = 0, ff = 1; char c = getchar();
    while(c<'0' || c>'9') { if(c=='-') ff = -1; c = getchar(); }
    while(c>='0'&&c<='9') { sum = sum * 10 + c - '0'; c = getchar(); }
    return sum * ff;
}

ll n,k;
ll a[N],b[2][N];
ll S=1;

inline ll ksm(ll aa,ll bb) {
	ll sum = 1;
	while(bb) {
		if(bb&1) sum = sum * aa %p;
		bb >>= 1; aa = aa * aa %p;
	}
	return sum;
}

int main() {
    n = read(); k = read();
    for(ll i=1;i<=n;i++) a[i] = read(), S = S * a[i] %p;
    b[0][0] = 1;
	for(int i=1;i<=n;i++) {
		int cl = i&1;
		b[cl][0] = b[cl^1][0] * a[i] %p;
		for(int j=1;j<=n;j++) {
			b[cl][j] = (a[i] * b[cl^1][j] - b[cl^1][j-1]) %p;
		}
	}
	ll mi = 1;
	for(int i=0;i<=n;i++) {
		(S -= b[n&1][i] * ksm(n,i*(p-2)) %p * mi %p - p) %= p;
		mi = mi * (k-i) %p;
	}
	cout<<(S%p+p)%p;
    return 0;
}
posted @ 2024-03-06 00:50  maple276  阅读(12)  评论(0编辑  收藏  举报