Lucky Conins
題意
最多共種硬幣,所有的硬幣之和不超過,每次將所有的硬幣拋出,第中硬幣正面朝上的概率爲,將反面朝上的硬幣移除掉.直至最後剩一種硬幣或沒有硬幣則停止.若最後剩餘一種硬幣,則稱這種硬幣是幸運的,求每種硬幣的幸運概率.
題解
推公式題.
假設我們要求第種硬幣成爲幸運硬幣的概率,那麼我們可以求其在第步成爲幸運硬幣的概率,然後對求和即可.
計算硬幣在步成爲幸運硬幣的概率:
一.第種硬幣,必須在第步至少剩個:
[1] :
硬幣在第步存活:,在第步及之前死亡:,第種所有硬幣在第步都死亡,第種在第步至少剩餘一個硬幣
二. 第種硬幣,至少有一枚要在第步存活,第步死亡
先考慮對於第種硬幣,它至少有一枚硬幣第步存活,在第步死亡的概率.
假設第種有枚硬幣在第步存活,在第步死亡:
對從到求和,利用二項式定理我們得到了第種硬幣,它至少有一枚硬幣第步存活,在第步死亡的概率:
[2] : .
三.除第種之外的所有硬幣,至少有枚在步存活,在第步死亡
爲避免重複計算
設是不與相等的數中最小的.
我們考慮是第種硬幣起到了這個作用,那麼種以後的硬幣只要滿足在步及之前死光即可.
然後再考慮是種硬幣起到了這個作用,那麼種以後的硬幣只要滿足在步及之前死光即可,並且要滿足第種之前的硬幣必須不能起作用(即在步及之前就必須全部死光),否則會算重.
也就是說我們需要記錄表示種之前的硬幣全部在第步及之前就死光.記錄表示種之後的硬幣全都在第步及之前就死光.
其中,
那麼這部分的答案就是
四.最終公式
代碼
#include <iostream>
#include <algorithm>
#include <cstring>
#define pr(x) std::cout << #x << ':' << x << std::endl
#define rep(i,a,b) for(int i = a;i <= b;++i)
double p[11];
int cnt[11];
int n;
const int lim = 50;
double fastpow(double x,int n) {
double res = 1.0;
while(n) {
if(n&1) res *= x;
x *= x;
n >>= 1;
}
return res;
}
double f(int id,int x) {
return fastpow(1-fastpow(p[id],x),cnt[id]) - fastpow(1-fastpow(p[id],x-1),cnt[id]);
}
double calc(int i) {
double ans = 0;
rep(x,1,lim) {
double res = 1-fastpow(1-fastpow(p[i],x),cnt[i]);
double tmp = 0,lft = 1;
rep(j,1,n) {
if(j == i) continue;
double rgt = 1;
rep(t,j+1,n) {
if(i == t) continue;
rgt *= fastpow(1-fastpow(p[t],x),cnt[t]);
}
tmp += f(j,x)*lft*rgt;
lft *= fastpow(1-fastpow(p[j],x-1),cnt[j]);
}
ans += res * tmp;
}
return ans;
}
int main() {
int T;
std::cin >> T;
while(T--) {
std::cin >> n;
rep(i,1,n) {
std::cin >> cnt[i] >> p[i];
}
if(n == 1) {
printf("%.6f\n",1.0);
continue;
}
rep(i,1,n) {
if(i != 1) printf(" ");
printf("%.6f",calc(i));
}
puts("");
}
return 0;
}