zoukankan      html  css  js  c++  java
  • 收集邮票 (概率dp)

    收集邮票 (概率dp)

    题目描述

    (n) 种不同的邮票,皮皮想收集所有种类的邮票。唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是 (n) 种邮票中的哪一种是等概率的,概率均为 (frac{1}{n}) 。但是由于凡凡也很喜欢邮票,所以皮皮购买第 (k) 张邮票需要支付 (k) 元钱。 现在皮皮手中没有邮票,皮皮想知道自己得到所有种类的邮票需要花费的钱数目的期望。

    输入格式

    一行,一个数字 (N,Nleqslant 10000)

    输出格式

    要付出多少钱. 保留二位小数

    样例

    样例输入

    3
    

    样例输出

    21.25
    

    数据范围与提示

    (Nleqslant 10000)

    分析

    按照概率 (dp) 的套路,我们反向定义方程,反着推,定义 (f[i]) 为已经有了 (i) 种,还需要买几次。 (g[i]) 为已经有了 (i) 种,还需要多少钱。

    因为当前已经有了 (i) 种了,每种选的可能性相同,所以这一次选重复的概率为 (frac{i}{n}) ,此时的次数就是 (f[i] + 1) ,因为当前拿了一个重复的,所以还要多拿一次,所以加一。

    不重复的概率就是 (frac{n-i}{n}),次数就是 (f[i+1] + 1),因为没拿重复的,所以是拿了 (i+1) 种的步数加一。那么 (f[i]) 的转移就是:

    [f[i] = (f[i] + 1) imes frac{i}{n} + (f[i+1] + 1) imes frac{n-i}{n} ]

    化简一下就是:

    [f[i] = f[i+1] imes frac{n}{n-i} ]

    接下来考虑钱数的转移,每一次增加的价格就是取的次数,而拿重复的概率是 (frac{i}{n}),所以这部分就是 ((g[i]+f[i]+1) imes frac{i}{n})

    其次就是没有重复,那么这部分就是 ((g[i+1]+f[i+1]+1) imes frac{n-i}{n})

    所以总的就是 :

    [g[i] = (g[i]+f[i]+1) imes frac{i}{n} + (g[i+1]+f[i+1]+1) imes frac{n-i}{n} ]

    化简完就是:

    [g[i] = frac{i}{n-i} imes f[i] + g[i+1] + f[i+1] + frac{n}{n-i} ]

    然后倒着枚举,转移就很简单了。

    代码

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int L = 1 << 20;
    char buffer[L],*S,*T;
    #define getchar() (S == T &&(T = (S = buffer) + fread(buffer,1,L,stdin),S == T) ? EOF : *S++)
    const int maxn = 1e5 + 10;
    double f[maxn],g[maxn];
    inline int read(){
    	int s = 0,f = 1;
    	char ch = getchar();
    	while(!isdigit(ch)){
    		if(ch == '-')f = -1;
    		ch = getchar();
    	}
    	while(isdigit(ch)){
    		s = s * 10 + ch - '0';
    		ch = getchar();
    	}
    	return s * f;
    }
    int main(){
    	freopen("D.in","r",stdin);
    	freopen("D.out","w",stdout);
    	int n = read();
    	for(int i = n - 1; ~i ; --i){
    		f[i] = f[i+1] + (1.0 * n) / (1.0 * (n - i));		
    		g[i] = (1.0 * i) / (1.0 * (n - i)) * (f[i] + 1) + g[i+1] + f[i+1] + 1;
    	}
    	printf("%.2lf",g[0]);
    	return 0;
    }
    
  • 相关阅读:
    bzoj2395: [Balkan 2011]Timeismoney
    bzoj2725: [Violet 6]故乡的梦&&bzoj4400: tjoi2012 桥
    bzoj3047: Freda的传呼机&bzoj2125: 最短路
    bzoj2734: [HNOI2012]集合选数
    bzoj2728: [HNOI2012]与非
    bzoj2730: [HNOI2012]矿场搭建
    bzoj2727: [HNOI2012]双十字
    蓝桥杯-计蒜客之节假日
    蔡基姆拉尔森计算公式
    最长公共子串与最长公共子序列
  • 原文地址:https://www.cnblogs.com/Vocanda/p/13519808.html
Copyright © 2011-2022 走看看