首先可以看出,90抽必得5星卡 和 抽到5星普通卡 两种是独立的,所以可以用 出5星的抽卡次数期望 乘以 出5星终极卡的出5星次数期望,得到出5星终极卡的期望。
先算第二部分,出的第一个5星有0.5的可能是5星普通卡,0.5可能是5星终极卡,第一个是5星普通卡时第二个一定是终极卡,所以,1次抽出5星终极卡的概率是0.5,2次的也是0.5,期望就是 1×0.5+2×0.5=1.5
再算第一部分,可以想到用动态规划解决,dp[i] 代表第i次抽卡抽出5星的概率,第i次抽出,说明前面的i-1次都没抽出,可以得到状态转移方程:
dp[i]=(1−j<i∑dp[j])×p
这里的p在i=90是为1。
期望就是概率乘权值 E=∑i×dp[i]
这里在代码实现时采用前缀和优化,也就是将 dp[i] 变为 ∑dp[i],这步操作在统计完期望之后。
#include <iostream>
using namespace std;
double dp[91];
int main() {
double p;
cin >> p;
double cnt = 0; //记录总期望次数
for (int i = 1; i < 90; i++) {
dp[i] = (1 - dp[i - 1]) * p;
cnt += dp[i] * i;
dp[i] += dp[i - 1]; // 前缀和
}
cnt += 90 * (1 - dp[89]); // i = 90时特殊处理
cout << fixed;
cout.precision(7);
cout << cnt * 1.5 << "\n";
return 0;
}
p = float(input())
dp = [0] * 91
cnt = 0 # 记录总期望次数
for i in range(1, 90):
dp[i] = (1 - dp[i - 1]) * p
cnt += dp[i] * i
dp[i] += dp[i - 1] # 前缀和
cnt += 90 * (1 - dp[89]) # i=90时特殊处理
print(f"{cnt * 1.5:.7f}")
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
double p = sc.nextDouble();
double[] dp = new double[91];
double cnt = 0; //记录总期望次数
for(int i = 1 ; i < 90 ; i++) {
dp[i] = (1-dp[i-1]) * p;
cnt += dp[i] * i;
dp[i] += dp[i-1]; //前缀和
}
cnt += 90 * (1-dp[89]); //i=90时特殊处理
System.out.printf("%.7f\n", cnt *1.5);
}
}
米小游很喜欢抽卡的感觉,所以他写了个抽卡程序。
普通抽卡过程有三种抽卡结果,5星普通卡、5星终极卡和非5星卡。
抽到5星普通卡和5星终极卡的概率均为 2p ,抽到非5星卡的概率为 1−p 。
如果抽到了5星普通卡,则之后的抽卡结果将发生变化,变为 p 的概率抽到5星终极卡, 1−p 的概率抽到非5星卡。 如果连续89次都未抽到5星卡,则第90抽必然会抽到一张5星普通卡或5星终极卡。
现在米小游想问你,他写的这个抽卡程序抽到5星终极卡的抽卡次数期望是多少?
一个小数 p 表示抽卡概率,0<p<1
一个小数,表示抽到5星终极卡的抽卡次数期望。你的答案和正确答案的误差不超过10−6 即视为正确。
输入
0.001
输出
129.1649522