SOJ 4552 [期望,概率]
题目链接:【http://acm.scu.edu.cn/soj/problem.action?id=4552】
题意:给你n种卡牌,每种卡牌有无限多个,每次从中抽取一张卡牌,问:1、集齐这n种卡牌需要抽取次数的期望,2、抽取m次,刚好(要保证最后一抽牌刚好满足抽了n张不同的牌)集齐n张卡牌的概率。
数据范围:n<=15,m<=35;(尼玛,比赛的时候数据范围都不给清楚,只在discuss里面说了一下,还不通知)。
题解:对于第一问:公式n*(1+1/2+1/3+....+1/n);第二问:dp[i][j]:表示抽取i次,得到j张卡牌的概率。dp[i][j]->dp[i+1][j+1]+(n-j)/j;dp[i][j]->dp[i+1][j]+(j/n);
#include<bits/stdc++.h> using namespace std; int n, m; double dp[55][55]; int main () { while(~scanf("%d%d", &n, &m)) { if(n == 0)//当n等于0的时候,只有m也等于0的时候有意义 { if(m == 0) printf("0.000000 1.000000\n"); else printf("0.000000 0.000000\n"); continue; } double ans1 = 0.0; for(int i = 1; i <= n; i++)//期望 ans1 += double(1.0 / (double)i); ans1 *= (double)n; if(n > m)//非法状态 { printf("%.6f 0.000000\n", ans1); continue; } if(n == 1)//当n等于1的时候,只有m也等于1的时候有意义 { if(m == 1) printf("%.6f 1.000000\n", ans1); else printf("%.6f 0.000000\n", ans1); continue; } for(int i = 0; i <= 50; i++) for(int j = 0; j <= 50; j++) dp[i][j] = 0.0; dp[0][0] = 1.0;//dp[i][j]:表示抽取i次,得到j张卡牌的概率。 for(int i = 0; i <= m; i++) //选的次数 for(int j = 0; j <= n && j <= n; j++) //得到的卡牌 { dp[i + 1][j + 1] += dp[i][j] * double(double(n - j) / double(n)); dp[i + 1][j] += dp[i][j] * double(double(j) / double(n)); } //要保证最后一抽牌刚好满足抽了n张不同的牌 printf("%.6f %.6f\n", ans1, dp[m - 1][n - 1]*double(1.0 / (double)n)); } return 0; }
想的太多,做的太少。