bzoj 1426 收集邮票 期望dp

题面

题目传送门

解法

有一定思维难度的期望dp

  • 首先,如果直接强行求最后期望花钱的数量是不太可行的
  • 那么,我们不妨先求出期望买的张数,然后就可以比较方便地求出最后的答案
  • f[i] f [ i ] 表示已经收集到 i i 种不同的邮票,还需要再购买的邮票数的期望值,不妨就假设那i种邮票就是前 i i 种,因为我们并不关心到底购买到的是哪一种
  • 那么,关于f[i]的转移方程是比较容易得到的,考虑下一次买到的是什么,有 in i n 的概率会买到之前的 i i 张,有nin的概率会买到剩余没有被买到过的
  • 所以,我们就可以得到 f[i]=inf[i]+ninf[i+1]+1 f [ i ] = i n f [ i ] + n − i n f [ i + 1 ] + 1 。把这个式子转化一下,就变成 f[i]=f[i+1]+nni f [ i ] = f [ i + 1 ] + n n − i 。得到这个式子可以根据期望的线性性。
  • 然后,我们再设 g[i] g [ i ] 表示已经收集到 i i 种不同的邮票,还需要购买的期望代价
  • 可以发现,g的转移其实和 f f 很类似,可以得到g[i]=in(g[i]+f[i]+1)+nin(g[i+1]+f[i+1]+1),稍微移项一下就变成 g[i]=inif[i]+g[i+1]+f[i+1]+nni g [ i ] = i n − i f [ i ] + g [ i + 1 ] + f [ i + 1 ] + n n − i
  • 那么,我们最后的答案就是 g[0] g [ 0 ]
  • 本题主要运用期望的线性性,这个性质是解决期望问题的关键
  • 解决期望问题一般都是倒推
  • 时间复杂度: O(n) O ( n )

代码

#include <bits/stdc++.h>
#define double long double
#define N 10010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
    x = 0; int f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
double f[N], g[N];
int main() {
    int n; read(n); f[n] = g[n] = 0;
    for (int i = n - 1; ~i; i--) {
        f[i] = f[i + 1] + (double)n / (n - i);
        g[i] = (double)i / (n - i) * f[i] + g[i + 1] + f[i + 1] + (double)n / (n - i);
    }
    cout << fixed << setprecision(2) << g[0] << "\n";
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值