资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
输入格式
一行两个正整数n和m
输出格式
一个实数P表示答案,保留4位小数。
样例输入
2 3
样例输出
0.7500
数据规模和约定
1≤n,m≤20
我们用二维数组来表示拿i张凑齐j种的概率
显而易见:当i < j 时 dp[i][i] = 0 ;
当i >= j 时 : 当 j == 1 时 , 这时表示拿了n张最后只要求凑出一张,同时有n张印章,每种印章出现的概率应当相同:都是 1.0 / n 。所以dp[i][j] = pow((1.0/n) , i - 1) ;
:当 j != 1 时 , 这时候又会出现两种情况:第i种出现了重复和第i种没有重复
1.出现重复:dp[i][j] = dp[i - 1][j] * (j / n) 这里的(j / n) 表示第i种印章的可能性
2.没有重复:dp[i][j] = dp[i - 1][j - 1] * (n - (j - 1)) / n
最后加起来就是这种情况下的动态转移方程
AC代码:
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std ;
const int N = 28 ;
double dp[N][N] ;
int main() {
int n, m ; //n张集齐m种
cin >> n >> m ;
double p = 1.0 / n ;
for (int i = 1 ; i <= m ; i ++) {
for (int j = 1 ; j <= n ; j ++) {
if (i >= j ) {
if (j == 1)
dp[i][j] = pow(p, i - 1) ;
else
dp[i][j] = dp[i - 1][j] * (j * 1.0 / n) + dp[i - 1][j - 1] * ((n - j + 1) * 1.0 / n);
}
}
}
printf("%.4lf\n", dp[m][n]) ;
return 0 ;
}