Kids and Prizes SGU - 495
题意
有\(n\)个奖品,装在\(n\)个盒子内,每个盒子有且仅有一个奖品。
\(m\)个人,每人依次选奖品,选择方式是从\(n\)个盒子内随机选择一个盒子。
如果盒子内有奖品,则取走,否则没有获得任何奖品。
盒子始终是\(n\)个,空盒子也一直存在。
求送出奖品数量的期望。
分析
\(dp[i][j]\)表示前\(i\)个人选了\(j\)个奖品的概率。
\(Ans = \sum_{j=0}^{n} dp[m][j] * j\)
考虑转移
\(dp[i][j] = dp[i - 1][j] * \frac jn + dp[i - 1][j - 1] *\frac{n - j + 1}{n}\)(分别是第\(i\)个人是否取到礼物的概率)
\(dp[0][0]=1\)
时间复杂度\(O(n^2)\)
考虑优化
考虑物
\(f_i\)表示前\(i\)个人选择结束后剩下的奖品个数。
\(f_i = f_{i-1} - \frac {f_{i-1}}{n}\) 前半部分是没拿到奖品,后半部分是拿到奖品。
\(f_i = (1 - \frac1n)f_{i-1} = (1 - \frac 1n)^i f_0 = n(1 - \frac 1n) ^i\)(因为\(f_0 = n\)),可以实数快速幂优化。
\(Ans = n - f_m\)
code
#include<bits/stdc++.h>
using namespace std;
#define ld long double
ld ksm(ld x, int y){
ld ret = 1; for(; y; y >>= 1, x = x * x) if(y & 1) ret = ret * x;
return ret;
}
int n,m;
int main(){
scanf("%d%d",&n,&m);
printf("%.15Lf\n",(ld)n - (ld)n * ksm(1.0 - 1.0 / n, m));
return 0;
}