HDU5985Lucky Coins 【数学题】

本文介绍了一种通过多次抛掷不同类型的硬币来确定哪种硬币最幸运的方法,并提供了详细的算法实现过程。针对每种硬币的数量和正面向上的概率,计算其成为最幸运硬币的概率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值