Bestcoder-892-1001-Battle for Wosneth(HDU6838)

这篇博客探讨了一个回合制游戏的策略,其中Alice和Bob轮流攻击。Alice先手,攻击命中率为p%,Bob血量为m。游戏结束时Alice积分的期望是通过将游戏转化为Bob的血量和攻击概率的等效模型来计算的,涉及到概率、期望和逆元运算。最终公式为m - ((m*100/p - 1) *q/100) % 998244353,注意百分比转换和大数取模的问题。
摘要由CSDN通过智能技术生成

题目链接

题目链接(可提交)

题意:

回合制游戏,Alice和Bob两人轮流攻击。Alice先手,每次成功的攻击自己获得1分,并给Bob造成一点血量损失,攻击命中率为p%;Bob血量为m(1e9),当血量减为0时,游戏结束,每次成功的攻击扣去Alice积分1分,攻击命中率为q%。求游戏结束时Alice积分的期望,结果对998244353取模。

思路:

期望游戏完全可以利用等效思维去考虑,那么游戏即可等效为:Alice攻击力为p%,Bob攻击力为q%

不难发现,Alice自己所增加的积分一定为Bob的血量m,而至于Bob攻击所带来的积分减少,需要算出游戏回合数即可得出结果

回合数计算也很简单,无非是m/p%。而最后一回合Bob死亡无法攻击,因此Bob回合数比Alice少一个

于是最终答案即为:m-(m/p%-1)*q

一下有几个需要注意的地方:

1.千万别忘记p和q均为百分制数,所以别忘了除100

2.对于大数取模的计算,一定要注意及时取模,减法运算完成后别忘了补加模数避免负数的出现

3.对于除法,需要用逆元运算来代替,这里可以用扩展欧几里得来计算

4.最后就是关于回合数,可能会联想到取整操作而过度理解推断出(m-1)/p+1这样的公式,然而由于逆元运算下的除法操作并不会取整,所以并不需要额外的考虑。而题目中对于除法分子分母互质的描述,也并不需要模拟去实现,只是出题者对于逆元操作的提示。

最终的公式即为:m - (m*100/p - 1) *q/100 =

m - ( ( (m*100)%mod *ni(p))%mod -1 +mod)%mod *q)%mod *ni(100))%mod +mod)%mod

代码:

/*
Author Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const ll mod = 998244353;
const double eps = 1e-7;

long long gcd(long long a,long long b, long long &x,long long &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    else
    {
        long long r = gcd(b,a%b,y,x);
        y -= x * (a / b);
        return r;
    }
}

long long ni(long long a,long long n)
{
    long long x, y;
    long long d = gcd(a, n, x, y);
    long long ans;
    if(d == 1)
    {
        x %= n;
        x += n;
        x %= n;
        ans = (x % n);
        return ans;
    }
    else
    {
        return -1;
    }
}


int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll m,p,q;//,x,y;
        scanf("%lld%lld%lld",&m,&p,&q);
        ll t = (((m*100LL)%mod)*ni(p,mod))%mod;
        ll re100 = (((t-1LL+mod)%mod)*q)%mod;
        ll red = 100LL;
        /*ll gcdr = gcd(re100,red,x,y);
        cout << re100 << endl;
        while(gcdr!=1LL)
        {
            re100 /= gcdr;
            red /= gcdr;
            gcdr = gcd(re100,red,x,y);
        }*/
        int re = ((m-(re100%mod) * ni(red,mod))%mod+mod)%mod;
        printf("%d\n",re);
    }
    return 0;
}

/*
优化t计算:t=(m-1)/p+1
换用double修正t(不需要)
修正t计算:t=(m*100-1)/p+1
换用全long long计算
re增加结果取模
运用自写的gcd函数
去除结尾分子分母约分过程
re增加防负机制
删去除法
re100增加防负机制
及时取模
防负之前先取模
m利用原值
简化t计算
别总想着取整,期望考虑除法后置
细节
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值