Lucky Coins
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 233 Accepted Submission(s): 75
Problem Description
Bob has collected a lot of coins in different kinds. He wants to know which kind of coins is lucky. He finds out a lucky kind of coins by the following way. He tosses all the coins simultaneously, and then removes the coins that come up tails. He then tosses all the remaining coins and removes the coins that come up tails. He repeats the previous step until there is one kind of coins remaining or there are no coins remaining. If there is one kind of coins remaining, then this kind of coins is lucky. Given the number of coins and the probability that the coins come up heads after tossing for each kind, your task is to calculate the probability for each kind of coins that will be lucky.
Input
The first line is the number of test cases. For each test case, the first line contains an integer k representing the number of kinds. Each of the following k lines describes a kind of coins, which contains an integer and a real number representing the number of coins and the probability that the coins come up heads after tossing. It is guaranteed that the number of kinds is no more than 10, the total number of coins is no more than 1000000, and the probabilities that the coins come up heads after tossing are between 0.4 and 0.6.
Output
For each test case, output a line containing k real numbers with the precision of 6 digits, which are the probabilities of each kind of coins that will be lucky.
Sample Input
3
1
1000000 0.5
2
1 0.4
1 0.6
3
2 0.4
2 0.5
2 0.6
Sample Output
1.000000
0.210526 0.473684
0.124867 0.234823 0.420066
Source
2016ACM/ICPC亚洲区青岛站-重现赛(感谢中国石油大学)
die[i][j]=第i种硬币在前j步内死关的概率
alive[i][j]=第i种硬币第j步还没死光
设p = 硬币投出正面的概率,n为这种硬币个数
die[i][j] = (1 - p^j)^n
alive[i][j] = 1 - die[i][j]
假如第i种硬币 在第step+1步死光
那i成为luck硬币的概率为 : ∑step(alive[i][step]−alive[i][step+1])∗∏nj=1(j==i?1:die[j][step])
解析一下:
(alive[i][step]−alive[i][step+1])∗∏nj=1(j==i?1:die[j][step])表示第step步时,其他硬币在1到step步内死光了,只剩下i硬币存活,继续扔,i硬币在step+1步时死光了
也就是说(alive[i][step]−alive[i][step+1])∗∏nj=1(j==i?1:die[j][step])=i恰好在step+1步死光的情况下,成为luckCoin的概率(包含了i在第1到第step步成为luck的情况)
假如其他硬币在第j步时 (恰好在第j步) 全死了,就剩下硬币i (这时候i已经是luck Coin了)
这时候继续扔硬币i,直到i也死光了
假如在第k步i也死光
那i在第j步成为luck的概率=第j步时其他硬币全死光*(i活到第j步,j+1步时死光) + 第j步其他全死光*(i活到j+1步,j+2步时死光) + ....+ 第j步其他全死光*(i活到k-1,k步时死光)
注意当只有一种硬币时 特判概率为1(题面完全没讲到…..)
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<string>
#include<vector>
#include<deque>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include <string.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define INF 10000000007
const int N = 11;
const int maxSteps = 300;
double die[N][maxSteps];//die[i][j]=第i种硬币前j步死概率
double alive[N][maxSteps];//alive[i][j]=第i种硬币第j步还没死光
double quickMulti(double p,int n){
double ans=1;
while(n){
if(n&1){
ans*=p;
}
n>>=1;
p*=p;
}
return ans;
}
void initCoin(int t,int n,double p){
double nowP=p;
for(int step=1;step<maxSteps;++step){
die[t][step]=quickMulti(1-nowP,n);
nowP*=p;
}
for(int step=1;step<maxSteps;++step){
alive[t][step]=1-die[t][step];
}
}
void slove(int kinds){
for(int i=0;i<kinds;++i){
double ans=0;
for(int step=1;step<maxSteps-5;++step){
double tmp=alive[i][step]-alive[i][step+1];
for(int j=0;j<kinds;++j){
if(j!=i){
tmp*=die[j][step];
}
}
ans+=tmp;
}
printf("%.6f",ans);
if(i!=kinds-1){
putchar(' ');
}
}
putchar('\n');
}
int main()
{
//freopen("/home/lu/Documents/r.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--){
int kinds;
scanf("%d",&kinds);
for(int i=0;i<kinds;++i){
int n;
double p;
scanf("%d%lf",&n,&p);
initCoin(i,n,p);
}
if(kinds==1){
puts("1.000000");
}
else{
slove(kinds);
}
}
return 0;
}