1 条题解

  • 0
    @ 2026-5-17 19:49:37

    题意简述

    给定长度为 nn 的数组 aa 和整数 vv。执行 mm 次操作,每次操作均匀随机选择一个位置 p[1,n]p \in [1, n],然后对 ap,ap+1,,ana_p, a_{p+1}, \dots, a_n 加上 vv。求最终 i=1nai\prod_{i=1}^n a_i 的期望值,结果对 M=109+7M = 10^9 + 7 取模。


    思路分析

    1. 将增量视为随机变量

    设随机变量 xk,ix_{k,i} 表示第 kk 次操作对 aia_i 的增量。若该次操作选择的位置 pkip_k \le i,则 xk,i=vx_{k,i} = v;否则 xk,i=0x_{k,i} = 0
    操作完成后:

    ai=ai+k=1mxk,ia_i' = a_i + \sum_{k=1}^m x_{k,i}

    目标为计算:

    $$E\left[\prod_{i=1}^n \left(a_i + \sum_{k=1}^m x_{k,i}\right)\right] $$

    2. 展开乘积与期望的线性性

    将乘积完全展开,每一项是从 nn 个因子中各选一项(选 aia_i 或某个 xk,ix_{k,i})相乘。由期望的线性性,我们可对每一项单独求期望再求和。

    考虑展开式中的某一项。对于固定的操作 kk,假设它在下标集合 Sk[1,n]S_k \subseteq [1,n] 的位置上被选中(即该项中包含了 xk,i,iSkx_{k,i}, i \in S_k)。若 Sk=S_k = \emptyset,该操作对此项无贡献(相当于因子 11)。若 SkS_k \neq \emptyset,该项非零当且仅当 pkminSkp_k \le \min S_k,此时所有被选中的 xk,i=vx_{k,i} = v。因此该操作带来的因子期望为:

    $$E\left[\prod_{i \in S_k} x_{k,i}\right] = v^{|S_k|} \cdot \Pr(p_k \le \min S_k) = v^{|S_k|} \cdot \frac{\min S_k}{n} $$

    由于不同操作的 pkp_k 相互独立,整个项的期望等于各操作期望的乘积,再乘上那些选择了 aia_i 的常数因子。

    3. 动态规划状态设计

    为了高效计算所有项期望的总和,我们可以逐位置构建因子,同时维护有多少个不同的操作已经“出现”。这里“出现”是指该操作的最小选中位置已经确定。

    dp[i][j]\text{dp}[i][j] 表示:已经处理了前 ii 个位置(下标 1i1 \sim i),且在这些位置中,恰好有 jj 个不同的操作已经至少被选中一次(即它们的最小选中位置 i\le i)时,所有已构造的部分项期望之和。

    初始状态:dp[0][0]=1\text{dp}[0][0] = 1

    4. 状态转移

    当我们考虑第 ii 个因子(即 aia_i' 的组成)时,有两种选择:

    • 选择原始 aia_i 或已出现操作的贡献
      若前 i1i-1 个位置已有 jj 个操作出现,它们对当前位置 ii 一定会贡献 vv(因为它们的 pki1<ip_k \le i-1 < i)。加上 aia_i 自身,这部分贡献为 ai+jva_i + j \cdot v
      这类选择不会增加新操作,转移至 jj 不变:

      $$\text{dp}[i][j] \mathrel{+}= \text{dp}[i-1][j] \times (a_i + j \cdot v) $$
    • 选择一个新的操作
      我们要引入一个之前从未出现过的操作,并且该操作必须在位置 ii 首次被选中(即它的 pk=ip_k = i)。这样其最小选中位置就是 ii
      一次操作恰好在 ii 处首次出现的期望贡献为 vinv \cdot \frac{i}{n}。未使用的操作还有 mjm - j 个,从中任选一个作为新操作。因此转移为:

      $$\text{dp}[i][j+1] \mathrel{+}= \text{dp}[i-1][j] \times \frac{i \cdot v}{n} \times (m - j) $$

    在实现时,除法用模 MM 下的逆元处理,nn 的逆元可预处理。注意 jj 至多为 min(n,m)\min(n, m),复杂度 O(nmin(n,m))O(n \cdot \min(n, m)),在 n5000n \le 5000 时完全可行。

    5. 最终答案

    处理完所有 nn 个位置后,所有项都已计入对应的 dp[n][j]\text{dp}[n][j] 中(jj 为该项实际使用到的不同操作个数)。因此答案就是对所有可能的 jj 求和:

    $$\text{ans} = \sum_{j=0}^{\min(n,m)} \text{dp}[n][j] \bmod M $$

    复杂度

    • 时间复杂度:O(nmin(n,m))O(n \cdot \min(n, m)),即 O(n2)O(n^2)
    • 空间复杂度:O(n2)O(n^2) 或使用滚动数组优化至 O(n)O(n)

    参考代码(逻辑与标程一致)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 5008, P = 1e9 + 7;
    int n, m, v, a[N], dp[N][N];
    
    long long Pow(long long a, int k) {
        long long res = 1;
        while (k) {
            if (k & 1) res = res * a % P;
            a = a * a % P, k >>= 1;
        }
        return res;
    }
    
    int main() {
        cin >> n >> m >> v;
        for (int i = 1; i <= n; ++i) cin >> a[i];
        
        dp[0][0] = 1;
        long long inv_n = Pow(n, P - 2);
        
        for (int i = 1; i <= n; ++i) {
            long long coef = i * inv_n % P * v % P;  // v * i / n
            for (int j = 0; j < i; ++j) {
                // 选择新操作
                dp[i][j + 1] = (dp[i][j + 1] + dp[i - 1][j] * coef % P * (m - j)) % P;
                // 选择原始 a_i 或已出现的操作
                dp[i][j] = (dp[i][j] + dp[i - 1][j] * (a[i] + 1LL * j * v % P)) % P;
            }
        }
        
        int ans = 0;
        for (int j = 0; j <= n; ++j)
            ans = (ans + dp[n][j]) % P;
        cout << ans << '\n';
        return 0;
    }
    
    • 1

    信息

    ID
    7189
    时间
    1000ms
    内存
    256MiB
    难度
    (无)
    标签
    递交数
    0
    已通过
    0
    上传者