zoukankan      html  css  js  c++  java
  • Candy----HDU4465----数学题

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4465

    题目意思:

    有两个箱子,每个箱子装有N个糖果

    打开第一个箱子的概率是P,另外一个就是1-P

    当小明打开一个箱子的时候发现有糖果就会吃掉

    有一天,小明打开其中的一个箱子,发现没有糖果了,求另外一个箱子的糖果数量的期望

    这个公式其实是很好推的,枚举另外一个箱子剩余的数量来算就OK

    这里的n经过了+1处理,这样我们枚举没有拿空的那个箱子里面拿了i个,那么剩下的就是n-i-1个

    算概率的话,就是在前面的n+i-i次中我要在前面把拿空的箱子中拿n-1次再乘以概率p^n放,为什么前面是n-1,后面又是n呢?

    因为最后一次一定要拿空的这个才可以,同理如果是另一个箱子

    但是在算的时候不好算,因为要么是p^n后太小,要么是前面的组合数太大

    所以只能边组合边乘

    每次组合数可以用之前一个*(N+i-1)/i得到,为了避免爆double,

    当数大于N(因为最终结果不可能大于N)的时候,乘以概率来减小,记录乘了多少次概率,最后算的时候少乘。

    下面上代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    
    const double eps = 1e-12;
    
    double fun(double s,double p,int n)
    {
        while(n)
        {
            if(s<eps)
                return 0;
            if(n&1)
                s*=p;
            n = n>>1;
            p = p*p;
        }
        return s;
    }
    
    
    int main()
    {
        int n;
        double p;
        int ca = 1;
        while(~scanf("%d%lf",&n,&p))
        {
            double tmp1,tmp2;
            tmp1 = tmp2 = 1;
            double ans = 0;
            n++;
            int d=0;
            for(int i=0;i<n;i++)
            {
                if(i)
                {
                    tmp1 = tmp1*(1-p)*(n+i-1)/i;
                    tmp2 = tmp2*(p)*(n+i-1)/i;
                    while(tmp1>n || tmp2>n)
                    {
                        tmp1 = tmp1*p;
                        tmp2 = tmp2*(1-p);
                        d++;
                    }
                }
                ans += fun((n-i-1)*tmp1,p,n-d);
                ans += fun((n-i-1)*tmp2,1-p,n-d);
            }
            printf("Case %d: %.6f
    ",ca++,ans);
        }
        return 0;
    }
    


    除了这种方法以外,还有一种方法,神方法

    就是在计算的时候会出现p^n这一步,太小,那么我们可以利用ln把n拿下来,然后再用e^n拿回去

    具体见代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int main()
    {
        int n;
        double p;
        double p1,p2,s1,s2;
        int ca = 1;
    
        while(~scanf("%d%lf",&n,&p))
        {
            double c = 0;
            double ans = 0;
            p1 = log(p);
            p2 = log(1-p);
    
            //exp之后就是p^(n+1) or (1-p)^(n+1)
            s1 = (n+1)*p1;
            s2 = (n+1)*p2;
    
            for(int i=0;i<n;i++)
            {
                if(c+s1>-30 || c+s2>-30)//这一步一定要加,计算没意义,还会导致TLE
                ans += (exp(c+s1)+exp(c+s2))*(n-i);
                c+=log(n+i+1)-log(i+1);
                s1+=p2;
                s2+=p1;
            }
            printf("Case %d: %lf
    ",ca++,ans);
        }
    
        return 0;
    }
    
    




  • 相关阅读:
    R语言使用RMySQL连接及读写Mysql数据库
    sparkR介绍及安装
    信息熵的计算
    django学习-管理界面、视图
    django学习-数据库操作接口API--(CRUD)
    django学习-数据库配置-创建模型
    django学习-安装、创建应用、编写视图
    接口八问 & 接口测试质量评估标准
    robotframework-post request请求携带上一个请求返回的cookie
    pipenv安装包时一直卡在Locking [packages] dependencies…,换pypi源
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3206433.html
Copyright © 2011-2022 走看看