CF1874D Jellyfish and Miku 记录
题目链接:https://codeforces.com/problemset/problem/1874/D
题意简述
有一个 \(n + 1\) 个点的无向图(\(0 - n\)),第 \(i\) 条边连接点 \(i-1\) 与 \(i\),带有正整数边权 \(a_i\)。在这样的一个图上从点 \(0\) 开始随机游走,点 \(n\) 为吸收点,其余点以边权为概率权重选择连接的一条边。
在所有总和不超过 \(m\) 的边权分配中,求出最短的期望吸收时间。
\(1 \le n \le m \le 3000\)
题解(官解)
首先计算对一个已知的边权分配 \(a_i\) ,从点 \(0\) 开始的期望吸收时间。这是一个经典的概率论问题,记从点 \(i\) 开始的期望吸收时间为 \(E(i)\),则可以列出如下方程:
记 \(D(i) = E(i - 1) - E(i)\),则可以化简方程如下:
由数学归纳法可证 \(D(i) = 1 + 2 \sum\limits_{j = 1}^{i-1} \dfrac{a_j}{a_i} = 1 + 2 \dfrac{s_{i-1}}{a_i}\)。则有:
根据该式,可以使用 DP 求解问题。记 \(dp_{i, x}\) 为当 \(s_i = x\) 时 \(\sum\limits_{j =1} ^ i \dfrac{s_{j-1}}{a_j}\) 的最小值,每次枚举 \(a_i\) 更新,即得到 \(O(nm^2)\) 的解法。
如何优化这个解法?观察式子 \(\sum\limits_{i =1} ^ n \sum\limits_{j = 1}^{i-1} \dfrac{a_j}{a_i}\),若存在 \(a_i > a_{i+1}\),则交换这相邻的两项,式子一定变得更小,因此 \(a\) 是非递减序列,\(a_i \le \dfrac{m}{n - i + 1}\)。
根据调和级数相关结论以及 \(n = O(m)\),代码的时间复杂度为 \(O(m^2 \log m)\)。
代码实现(C++)
void solve() {
    int n, m;
    cin >> n >> m;
    vector dp(n + 1, vector<double>(m + 1, INFINITY));
    dp[0][0] = 0;
    for (int i = 0; i < n; i++) {
        for (int x = 0; x <= m; x++) {
            for (int y = 1; x + y * (n - i) <= m; y++) {
                dp[i + 1][x + y] = min(dp[i + 1][x + y], dp[i][x] + x * 1.0 / y);
            }
        }
    }
    cout << fixed << setprecision(15) << dp[n][m] * 2 + n << "\n";
}
 
                    
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号