题意:一个人从坐标0开始,有1/4的概率向左走一格,1/4的概率向右走一格,1/2的概率不动,给出步数n,和最终的位置m,求到m的概率为多少。该概率可表示为p/q,p,q互质,求出p*q的逆元即可。

思路:类似规律题?

先画下图:

Markdown

Markdown

Markdown

可以找规律得到这是一个杨辉三角。

杨辉三角的第n行第m个数可表示为C(m-1,n-1)。

所以题目要求的就是C(m+n,2*n)/4^n。

那如何求4^n的逆元呢?根据费马小定理+逆元的定义,可知a关于m的逆元是img

所以4^n的逆元就是4^(n×MOD-2×n)。

组合数可以用卢卡斯定理,这里要注意m可能是负的,所以要取绝对值!

代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#define INF 0x3f3f3f3f
#define MOD 1000000007
using namespace std;
typedef long long ll;
long long PowerMod(long long a,long long b,long long c)
{
    long long ans=1;
    long long k;
    k=a;
    k=k%c;
    while(b>0)
    {
        if(b&1)
        ans=(ans*k)%c;
        b>>=1;
        k=(k*k)%c;
    }
    return ans;
}
long long C(long long n,long long m,long long p)
{
    if(m>n)return 0;
    long long ans = 1;
    for(int i=1;i<=m;i++)
    {
        long long a=(n+i-m)%p;
        long long b=i%p;
        ans=ans*(a*PowerMod(b,p-2,p)%p)%p;
    }
    return ans;
}
long long Lucas(long long n,long long m,long long p)
{
    if(m==0)return 1;
    return C(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;
}
int main()
{
    int t;
    ll n,m;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&m);
        if(n==0&&m==0)printf("1\n");
        else if(n==0)printf("0\n");
        else
        {
            if(m<0)m=-m;
            ll x=Lucas(n*2,m+n,MOD);
            ll y=PowerMod(4,(n*MOD-2*n),MOD);
            printf("%lld\n",(x*y)%MOD);
        }
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

高斯消元 Previous
java高精度模板 Next