2017 ACM-ICPC 亚洲区(西安赛区)网络赛b题Coin(矩阵快速幂)

本文介绍了一种使用矩阵快速幂求解特定概率问题的方法。针对抛掷硬币实验中正面向上次数为偶数的概率计算,文章详细阐述了如何通过矩阵运算结合快速幂技巧高效解决此类问题,并给出了完整的C++实现代码。

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

这里写图片描述

题意:给出抛一个硬币正面向上的概率,求抛k次,有偶数次向上的概率,用x乘y的逆元来表示
y的逆元可以用扩展欧几里得求,难点在于求x,显然y等于p的k次方,然后x等于((p-q)+p)的k次方里含p的偶数次方项的和。比赛时想了很久,突然发现,和求⌈(a+b√n⌉%m有点类似,于是想到矩阵快速幂。代码如下

#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
const long long mod= 1e9+7;
long long exgcd(long long a,long long b,long long &x,long long &y)//拓展欧几里得
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    long long ret=exgcd(b,a%b,x,y);
    long long tmp=x;
    x=y;
    y=tmp-a/b*y;
    return ret;    //返回(a,b)
}
long long mod_pow(long long x, long long n, long long mod)//快速幂取模
{
    long long res = 1;
    x = x % mod;
    while(n > 0)
    {
        if(n & 1)
        {
            res = res * x % mod;
        }
        x = x * x % mod;
        n >>= 1;
    }
    return res;
}
struct Matrix
{
    long long ma[2][2];
};
Matrix mul(const Matrix &a,const Matrix &b)
{
    Matrix c;
    memset(c.ma,0,sizeof(c.ma));
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            for(int k=0;k<2;k++)
            {
                c.ma[i][j]=(c.ma[i][j]+a.ma[i][k]*b.ma[k][j])%mod;
            }
        }
    }
    return c;
}
Matrix qmul(Matrix a,int k)//矩阵快速幂
{
    Matrix b;memset(b.ma,0,sizeof(b.ma));
    for(int i=0;i<2;i++) b.ma[i][i]=1;
    while(k>0)
    {
        if(k&1) b=mul(b,a);
        a=mul(a,a);
        k/=2;
    }
    return b;
}
int main()
{
    long long T,q,p,k;
    scanf("%lld",&T);
    while(T--)
    {
        scanf("%lld%lld%lld",&p,&q,&k);
        long long xx,yy;
        Matrix a;
        a.ma[0][0]=p-q;a.ma[1][1]=p-q;//构造矩阵
        a.ma[0][1]=q;a.ma[1][0]=q;
        Matrix ans=qmul(a,k-1);
        long long x1=((p-q)*ans.ma[0][0]+q*ans.ma[1][0])%mod;
        p=mod_pow(p,k,mod);
        exgcd(p,mod,xx,yy);
        xx=(xx%mod+mod)%mod;
        long long ans1=(x1*xx)%mod;
        printf("%lld\n",ans1);
    }return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值