CF1842G 题解

· · 题解

组合意义保平安。

题意

有一个长度为 n 的数组 a 和常数 v,对数组进行 m 次操作,每一次操作中,均匀随机一个 [1, n] 中的整数 p,对于所有 p \leq i \leq n,让 a_i \gets a_i + v,求最后 \prod\limits_{i=1}^n a_i 的期望值,对 10^9 + 7 取模。

#### 题解 考虑 $\prod a_i$ 的组合意义,相当于有一个 $n+1$ 个点顺次连接形成的道路,一个人从第 $1$ 个点出发,从第 $i$ 个点走到第 $i+1$ 个点有 $a_i$ 种方案,问这个人走到 $n+1$ 共有多少种方案。 而修改的意义是什么呢,相当于在 $p$ 处放下了一个神奇妙妙工具,这个人走到 $p$ 的时候会拿起这个工具,之后对于任意的 $i$,可以选一个手上有的工具以 $v$ 的方案数从 $i$ 走到 $i+1$。 注意到被使用过的工具数量不超过 $n$,可以考虑在 DP 时记录这个状态,复杂度应该能降下来。 具体地,定义 $f_{i, j}$ 表示考虑了前 $i$ 处,使用了 $j$ 个工具的方案数,转移分三类: 1. 使用 $a_{i+1}$,$f_{i + 1, j} \gets f_{i, j} \cdot a_{i+1}$; 2. 使用一个被使用过的工具,$f_{i+1, j} \gets f_{i, j} \cdot j \cdot v$; 3. 使用一个还未被使用过的工具,需要先确定这个工具是哪里来的,$f_{i+1, j+1} \gets f_{i, j} \cdot (i+1) \cdot (m-j)\cdot v$。 最后的答案即为 $\sum\limits_i \frac{f_{n, i}}{n^i}$。 #### 代码 ```cpp #include <cstdio> #include <cstring> #include <algorithm> typedef long long ll; typedef unsigned long long ull; const int N = 5005, mod = 1000000007; int n, m, v, a[N], f[N][N]; inline int qpow(int x, int y) { int res = 1; for (; y; y >>= 1, x = 1ll * x * x % mod) if (y & 1) res = 1ll * res * x % mod; return res; } int main(void) { scanf("%d%d%d", &n, &m, &v); for (int i = 1; i <= n;++i) scanf("%d", a + i); f[0][0] = 1; for (int i = 0;i < n;++i) for (int j = 0; j <= std::min(m, i);++j) { f[i + 1][j] = (f[i + 1][j] + 1ll * f[i][j] * a[i + 1]) % mod; f[i + 1][j] = (f[i + 1][j] + 1ll * f[i][j] * j % mod * v) % mod; f[i + 1][j + 1] = (f[i + 1][j + 1] + 1ll * f[i][j] * (i + 1) % mod * v % mod * (m - j)) % mod; } int res = 0; int iv = qpow(n, mod - 2); for (int i = 0; i <= std::min(n, m); ++i) res = (res + 1ll * f[n][i] * qpow(iv, i)) % mod; printf("%d\n", res); return 0; } ```