HDU1410-PK武林盟主

216 篇文章 0 订阅
8 篇文章 0 订阅

PK武林盟主

                                                                            Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
                                                                                                       Total Submission(s): 1448    Accepted Submission(s): 380


Problem Description
枫之羽认为自己很强,想当武林盟主,于是找现任武林盟主氢氧化铜挑战。氢氧化铜欣然接受了挑战,两人约好于下个月的月圆之夜在HDU校园内的三根柱子上进行决战。这场PK赛肯定能吸引武林中所有人前来观战,所以他们找了有商业运作潜力的经济人你,让你来组织这场百年一见的世纪之战,假设两人都有一定的血HP1、HP2.HP1是枫之羽的,HP2是氢氧化铜的。他们也有一定攻击力AP1、AP2,AP1是枫之羽的,AP2是氢氧化铜的。当进行攻击时,对方的HP减少自己的攻击力,比如HP1=2 HP2=1 AP1=1 AP2=1,当氢氧化铜攻击枫之羽时,枫之羽的HP=2(原先的HP1)-1(氢氧化铜的AP2)=1。现在两个人对决很多回合,每回合不是枫之羽攻击氢氧化铜,就是氢氧化铜攻击枫之羽。求枫之羽能赢氢氧化铜成为下任武林盟主的的胜率。
 

Input
该题含有多组测试数据,每行为HP1,HP2,AP1和AP2 (1<=HP1,HP2,AP1,AP2<=32767)
 

Output
每组数据输出一行,为枫之羽赢氢氧化铜概率的值 (结果保留4位小数).
 

Sample Input
  
  
2 1 1 1
 

Sample Output
  
  
75.0000
 

Author
Eddy
 

Source
 

       解题思路:设枫之羽为A,氢氧化铜为B,A需要打N1次才能打败B,B需要打N2次才能打败A,而A战胜B的情况必定是A打了N1次,且最后一次是A打B。设B打了i次(i < N2),则此种情况发生的概率为:C(N - 1, i) * pow(0.5, N1 + i);那么A战胜B的概率便是i由0到N2 - 1所有情况中上式的累加。(排列公式:A(n,m)=n!/(n-m)!
组合公式:C(n,m)=n!/(m!*(n-m)!), C(n,m)=C(n,n-m))

代码如下:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <climits>

using namespace std;

double mypow(double x,int y)
{
    double sum=1;
    while(y)
    {
        if(y&1) sum*=x;
        x*=x;
        y>>=1;
    }
    return sum;
}

int main()
{
    int h1,h2,a1,a2,x1,x2;
    while(~scanf("%d %d %d %d",&h1,&h2,&a1,&a2))
    {
        double ans;
        int k=1;
        x1=h2/a1;x2=h1/a2;
        if(h2%a1>0) x1++;
        if(h1%a2>0) x2++;
        ans=mypow(0.5,x1);
        for(int i=1;i<x2;i++)
        {
            k*=(x1-1+i)/i;
            ans+=1.0*k*mypow(0.5,x1+i);
        }
        printf("%.4lf\n",ans*100);
    }
    return 0;
}

由于浮点数乘除会出现误差,而再乘以一个较大的数会使误差扩大,导致Wrong Answer,因此进行对数转换并进行优化:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <climits>

using namespace std;

double mypow(double x,int y)
{
    double sum=1;
    while(y)
    {
        if(y&1) sum*=x;
        x*=x;
        y>>=1;
    }
    return sum;
}

int main()
{
    int h1,h2,a1,a2,x1,x2;
    while(~scanf("%d %d %d %d",&h1,&h2,&a1,&a2))
    {
        double ans,k=0;
        x1= h2/a1;
        x2=h1/a2;
        if(h2%a1>0) x1++;
        if(h1%a2>0) x2++;
        ans=mypow(0.5,x1);
        for(int i=1; i<x2; i++)
        {
            k+=log10(x1-1.0+i)-log10(1.0*i);
            ans+=pow(10,k+(x1+i)*log10(0.5));
        }
        printf("%.4lf\n",ans*100);
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值