Lust 题解

CF446E

很好的一道 EGF 入门题。


我们发现每一操作一次,答案增加多少,\(\prod a_i\) 就减小多少。

于是答案即为 \(\prod a_i-\prod (a_i-b_i)\),其中 \(b_i\) 为在 \(i\) 位子上操作的次数。

显然我们只需算出后面这坨的期望就行了,前面是固定的。

期望是困难的,先化为普通式子。

\[\begin{align*} & \mathbb E\left[\prod \left(a_i - b_i\right)\right]\\ =& \cfrac{1}{n^k}\sum_{\sum b_i=k} \cfrac{k!}{\prod b_i!}\prod\left(a_i-b_i\right)\\ =& \cfrac{k!}{n^k}\sum_{\sum b_i = k}\prod \cfrac{a_i-b_i}{b_i!} \end{align*} \]

注意求和的那坨式子,看到 \(\sum b_i=k\) 在条件上就想 \(\cdots\) 嗯,生成函数。

说来就来,写出 :

\[\hat F(x) = \sum_{i=0}^\infty \left(\sum_{\sum b_j = i}\prod \cfrac{a_j-b_j}{b_j!}\right)x^i \]

再把求和后面那一坨拎出来:

\[\begin{align*} &\hat G_i(x)\\ =& \sum_{j=0}^\infty \cfrac{a_i - j}{j!}x^j \\ =& \sum \cfrac{a_i}{j!}x^j - \sum\cfrac{1}{\left(j - 1\right)!}x^j\\ =&a_ie^x-x\sum \cfrac{1}{\left(j - 1\right)!}x^{j-1}\\ =&(a_i-x)e^x \end{align*} \]

发现 \(\hat F\) 就是 \(\hat G\) 的加法和卷积,所以:

\[\begin{align*} & \hat F(x)\\ =& \prod \hat G_i(x) \\ =& \prod\left(a_i-x\right)e^x\\ =& e^{nx}\prod \left(a_i-x\right)\\ =& \left[\prod\left(a_i-x\right)\right]\sum \cfrac{x^in^i}{i!} \end{align*} \]

左边这个求积的各项系数显然可以求出(方法放在后面),设其为 \(H(x)=\sum h_ix^i\)

所以答案即为:

\[\begin{align*} &\mathbb E\left(ans\right)\\ =& \prod a_i - \cfrac{k!}{n^k} \left[x^k\right]\hat F(x)\\ =& \prod a_i -\sum \cfrac{h_in^{k-i}}{\left(k - i\right)!}\\ =& \prod a_i - \sum \cfrac{h_ik!}{\left(k - i\right)!n^i} \end{align*} \]

这里就做完了。


现在我们回过头来想怎么求出 \(h_i\)

我们想的是 \(\prod_{i=0}^n \left(a_i-x\right)\) 的系数,但是我们可以从 \(\prod_{i=0}^{n-1} \left(a_i-x\right)\) 的系数推出,只需要给每个位置项都乘上 \((a_n-x)\) 再更新到系数上就行了。

以此类推,只要从 \(n=0\) 的情况不断递推即可。

代码还是相当好写的。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
constexpr int MAXN = 5005;
constexpr int MOD = 1e9 + 7;
int qpow(int x, int y) {
    int ans = 1;
    while (y) {
        if (y & 1)
            ans = ans * x % MOD;
        x = x * x % MOD;
        y >>= 1;
    }
    return ans;
}
int a, n, k, c[MAXN];
signed main() {
    cin >> n >> k;
    c[0] = 1;
    rep (i, 1, n) {
        cin >> a;
        per (j, i, 1) {
            c[j] *= a;
            c[j] -= c[j - 1];
            c[j] = (c[j] + MOD) % MOD;
        }
        (c[0] *= a) %= MOD;
    }
    int ans = c[0], pw = 1;
    rep (i, 0, n) {
        (ans += MOD - pw * c[i] % MOD) %= MOD;
        (pw *= (k - i) * qpow(n, MOD - 2) % MOD) %= MOD;
    }
    cout << ans << endl;
    return 0;
}
posted @ 2025-01-31 21:38  LightningCreeper  阅读(4)  评论(0编辑  收藏  举报