Codeforces - Gym - 101778A - Will he Die? - (Lucas定理,组合数,除法逆元)

题目链接:http://codeforces.com/gym/101778/problem/A

题意:有一个坐标轴,现在处在起点(坐标为0),题目给出n和m,问走m步正好到达点坐标为n处的概率,对于在每个点往左往右走的概率相同。

解析:可惜的一题,比赛时思路正确,公式正确,解法正确,但是没想到怎么优化求组合数,所以超时,当然还差些细节。

由于往左往右情况相同,所以先对n求绝对值

1.如果n>m,那么就不可能到达n,此时输出0

2.如果n<=m,此时能够到达n,假设n在左边,假设往左走了l步,往右走了r步,有公式:

①.l+r=m;②l-r=n;可得l=(m+n)/2

那么这种走法的概率就是:C(m,l)*0.5^l*0.5^r,对应题目中概率公式p/q,这里q=2^(l+r);p=C(m,r)

由于涉及求余操作,这里要用到组合数求余方法Lucas定理和除法求余即(1/x)%mod=pow_mod(x,mod-2);

注意:由于情况2时往左走了n步,那么多余的步数(m-n)一定是往左一步对应往右一步的(这样才不会破坏总距离为n的前提),所以(m-n)一定为偶数,否者同情况1一样不能到达n。

最后在得到p和q之后,由于有公式,所以答案z=p/q,z等于p乘q的除法逆元。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
const ll M=2*1e5+5;
ll fact[M],ifact[M];//fact[i]是i的阶乘,ifact[i]是阶乘的除法逆元,两者用于求组合数

ll pow_mod(ll n,ll k,ll mod) //快速幂求n^k余m的结果
{
    ll res=1;
    n=n%mod;
    while(k>0)
    {
        if(k&1)
            res=res*n%mod;
        n=n*n%mod;
        k>>=1;
    }
    return res;
}
void init()//初始化
{
    fact[0]=ifact[0]=1;
	for(int i=1;i<M;++i)
    {
        fact[i]=(fact[i-1]*i)%MOD;
		ifact[i]=pow_mod(fact[i],MOD-2,MOD);
	}
}

ll C(ll n,ll m)//求组合数
{
    if(n<m)
        return 0;
    return  fact[n]*ifact[m]%MOD*ifact[n-m]%MOD;
}

ll Lucas(ll n,ll m)//Lucas定理求C(n,m)%mod
{
    if(m==0)
        return 1;
    return C(n%MOD,m%MOD)*Lucas(n/MOD,m/MOD)%MOD;
}
int main()
{
    init();
    ll n,m;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&n,&m);
        n=abs(n);
        ll ans;
        if(n>m||((m-n)&1))
        {
            ans=0;
        }else
        {
            ll q=pow_mod(2,m,MOD);
            ll p=Lucas(m,m-(m+n)/2);
            //cout<<q<<"        "<<p<<endl;
            ans=p*pow_mod(q,MOD-2,MOD)%MOD;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值