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;
}