题目链接:https://www.luogu.com.cn/problem/P4550

解题思路:

定义状态 \(f_i\) 表示目前已经取到 \(i\) 种邮票的情况下,取完所有 \(n\)

很明显,\(f_n = 0\),因为此时已经取完了 \(n\)

如果当前已经取到了 \(i\)

  • 有 \(\frac{i}{n}\) 的概率取到现有的邮票(此时仍然拥有 \(i\)
  • 有 \(1 - \frac{i}{n}\) 的概率取到没有的邮票(此时拥有了 \(i+1\)

所以,当 \(i \lt n\)

\[f_i = \frac{i}{n} f_i + (1 - \frac{i}{n}) f_{i+1} + 1 \]

(多出来的 \(1\)

化简得到:

\(\frac{n-i}{n} f_i = \frac{n-i}{n} f_{i+1} + 1\)

\(\rightarrow\)

当 \(i \lt n\)

\[f_i = f_{i+1} + \frac{n}{n-i} \]

定义状态 \(g_i\) 表示目前已经取到 \(i\) 种邮票的情况下,取完所有 \(n\)

"第 \(k\) 次取的花费为 \(k\)"。\(\Rightarrow\) 但是这么分析会很麻烦,我们可以把问题转换为 "倒数第 \(k\) 次取的花费为 \(k\)"

这两句话其实是等价的:

因为假设取 \(m\)

  • 按照 "第 \(k\) 次取的花费为 \(k\)" 总的花费为 \(1 + 2 + 3 + \ldots + m = \sum\limits_{i=1}^m i\);
  • 按照 “倒数第 \(k\) 次取的花费为 \(k\)” 总的花费为 \(m + (m-1) + (m-2) + \ldots + 2 + 1 = \sum\limits_{i=1}^m i\)$。

但是按照这样分析,接下来解决起来会好理解很多。这也是我在看 洛谷上的题解 的时候(我感觉)前几篇题解没有讲的很清楚的地方 后几篇的题解我没看

而取到 \(i\) 种不同的邮票的期望次数是 \(f_i\) 次,所以在拥有 \(i\) 种不同邮票的情况下,要取完 \(n\) 种邮票的期望次数是 \(f_i\)

  • 此时如果取到的是一张现有的邮票,则我还有 \(f_i\) 次要取,我这次的期望取的次数是倒数第 \(f_i + 1\) 次,花费为 \(f_i + 1\);
  • 此时如果取到的是一张新的邮票,则我还有 \(f_{i+1}\) 次要取,我这次的期望取的次数是倒数第 \(f_{i+1} + 1\) 次,花费为 \(f_{i+1} + 1\)

此时我:

  • 有 \(\frac{i}{n}\) 的概率取到现有的邮票(此时仍然拥有 \(i\)
  • 有 \(1 - \frac{i}{n}\) 的概率取到没有的邮票(此时拥有了 \(i+1\)

所以,当 \(i \lt n\)

\[g_i = \frac{i}{n} (g_i + f_i + 1) + (1 - \frac{i}{n}) (g_{i+1} + f_{i+1} + 1) \]

化简得到:

\(\frac{n-i}{n} g_i = \frac{i}{n} (f_i + 1) + \frac{n-i}{n} (g_{i+1} + f_{i+1} + 1)\)

\(\Rightarrow\)

\[g_i = g_{i+1} + f_{i+1} + 1 + \frac{i}{n-i} (f_i + 1) \]

最终的答案为 \(g_0\)。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 5;
double f[maxn], g[maxn];
int n;

int main() {
    cin >> n;
    for (int i = n-1; i >= 0; i--)
        f[i] = f[i+1] + 1. * n / (n - i),
        g[i] = g[i+1] + f[i+1] + 1 + 1. * i / (n - i) * (f[i] + 1);
    printf("%.2lf\n", g[0]);
    return 0;
}