HDU 4465 Candy--数学求期望

题目链接

题目大意 :两个盒子开始都有n块糖,每次从一个中拿糖的概率为p,求当一个盒子空时,另一个盒子中糖的数目期望




很明显,200000太大了,不能直接排列组合。
然后需要一个快速排列组合函数:logC(m,n)
<span style="font-size:14px;">f[0]=0;
for(int i=1;i<=400002;i++) f[i]=f[i-1]+log(i*1.0);
double logC(int m,int n){
    return f[m]-f[n]-f[m-n];
}</span>

有了上面的算式之后,C(m,n)=exp(logC(m,n))
问题解决了吧。

但是其实问题没有解决,我们在比赛的时候想了一个小时,怎么处理double的上溢出和下溢出。。。
最后被函数中的log给提醒了。直接全部取log不就好了!
数值计算方法没学好啊hdu 4465 Candy 快速全排列 2012 Asia Chengdu Regional Contest B - Mike - Apple

所以算式变为
hdu 4465 Candy 快速全排列 2012 Asia Chengdu Regional Contest B - Mike - Apple
<span style="font-size:14px;">#include<cstdio>
#include<cmath>
double f[400005];
double logC(int m,int n){
    return f[m]-f[n]-f[m-n];
}
int main(){
    f[0]=0;
    for(int i=1;i<=400002;i++) f[i]=f[i-1]+log(i*1.0);
    int apple=1,n;
    double p,q;
    while(~scanf("%d",&n)){
        scanf("%lf",&p);
        q=1-p;
        double ans=0;
        for(int k=0;k<=n;k++){
            ans+=(n-k)*(exp(logC(n+k,k)+(n+1)*log(q*1.0)+k*log(p*1.0))+exp(logC(n+k,k)+(n+1)*log(p*1.0)+k*log(q*1.0)));
        }
        printf("Case %d: %.6f\n",apple++,ans);
    }
    return 0;
}</span>

法二:

题目分析 :不难得到公式: ans = 求和(i = 0~n)(n-i)  * C(i, n + i) * ( (p ^ n* (1 - p) ^ i) + (p ^ i + (1 - p) ^ n)),

本题n上限为20000,组合数存不下故中间过程要用递推公式即an = an * n / (n + 1) *(n + i) / i * p这样还是会卡精度有点坑爹,可以采用一个很简单的技巧。见程序

<span style="font-size:14px;">#include <cstdio>
#include <cmath>
int main()
{
    int n, ca = 0;
    double p;
    while(scanf("%d %lf", &n, &p) != EOF)
    {
        double tmp1 = n, tmp2 = n ;
        // printf("tmp1 = %f  tmp2 = %f\n", tmp1, tmp2);
        double ans1 = tmp1 * pow(1 - p, n + 1);
        double ans2 = tmp2 * pow(p, n + 1);
        int now = n;
        int re = n + 1;
        for(int i = 1; i < n; i++)
        {
            now = n - i; //系数
            //递推公式
            tmp1 *= 1.0  / (double)(now + 1) * p / i * (n + i) * now;
            tmp2 *= 1.0  / (double)(now + 1) * (1 - p) / i * (n + i) * now;
            //当tmp大于某个设定的值时让它乘p(或(1-p))来保证其数字不会暴精度
            //关键技巧
            while(tmp1 > n || tmp2 > n)
            {
                tmp1 *= (1 - p);
                tmp2 *= p;
                re--;
            }
            //因为每一项都要乘pow(1-p, n+1)或pow(p,n+1)
            //我们在此补上剩余未乘的p(或(1-p))的幂数即可
            ans1 += tmp1 * pow(1 - p, re);
            ans2 += tmp2 * pow(p, re);
           // printf("tmp1 = %lf   tmp2 = %lf  \n", tmp1, tmp2);
        }
        printf("Case %d: %lf\n", ++ca, ans1 + ans2);
    }
}
</span>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值