[SRM695-900]BearEmptyCoin

本文介绍了一种通过编程解决特定硬币游戏问题的方法,重点在于如何最大化甩动硬币获得的分数总和的概率。文中详细解释了算法思路,并提供了一个具体的C++实现案例。

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

题目大意

有一个两面为空的硬币,正面和反面有区别。
你需要甩kk次,每次其会有一面朝上,如果该面为空,你填一个整数上去,若不为空,获得该分数。
你希望最大化分数和为s的概率。

做法

如果s mod k=0s mod k=0显然我们不管哪面都会填s/ks/k,输出2k2k
你能决定的是第一次摇到第2个面时,根据这是第几次决定另一面填啥。设这个为yy,第一次填上去的就是x,那么xx是定值,你要提前准备。
下面我们令x表示正面,yy表示反面(实际上由于正反面有区别,答案要乘2)。
设有A次出现正面。
那么要满足Ax+(kA)y=SAx+(k−A)y=S
显然要有(A,kA)|S(A,k−A)|S(A,k)|S(A,k)|S
我们可以证明,存在一个xx,对于满足(A,k)|SAA,都存在一个对应y满足Ax+(kA)y=SAx+(k−A)y=S
Ax+(kA)y=SAx+(k−A)y=S
(kA)(yx)=Skx(k−A)(y−x)=S−kx
由于AAkA对称可以得到A|SkxA|S−kx
所以有lcm(A)|Skxlcm(A)|S−kx
lcm(A)p+kx=Slcm(A)∗p+kx=S
我们知道一个简单的结论:
如果(a,c)|d,(b,c)|d([a,b],c)|d(a,c)|d,(b,c)|d,那么有([a,b],c)|d。这个结论的证明可以考虑从gcd以及lcm的本质出发,即对质因子次数取min与取max。
那么因为每个AA都满足(A,k)|S于是有(lcm(A),k)|S(lcm(A),k)|S
因此我们证明了这个xx一定存在。
接下来就好做了,答案是
j=1k1maxi=0kj1[(i+j,k)|S]Ckj1i
事实上这个kk开到10^5当然也是能做的。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=60+10;
ll c[maxn][maxn];
int i,j,k,l,n,m,s;
ll ans,t;
class BearEmptyCoin{
    int gcd(int a,int b){
        return b?gcd(b,a%b):a;
    }
    public:
    ll winProbability(int K,int S){
        k=K;
        s=S;
        if (s%k==0){
            ans=1;
            fo(i,1,k) ans*=2;
            return ans;
        }
        c[0][0]=1;
        fo(i,1,k){
            c[i][0]=1;
            fo(j,1,i) c[i][j]=c[i-1][j]+c[i-1][j-1];
        }
        ans=0;
        fo(j,1,k-1){
            t=0;
            fo(i,0,k-j-1)
                if (s%gcd(i+j,k)==0) t=max(t,c[k-j-1][i]);
            ans+=t;
        }
        return ans*2;
    }
} zlt;
int main(){
    printf("%lld\n",zlt.winProbability(2,-49));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值