首页 > 代码库 > [组合数取模-逆元计算模板] zoj 3624 Count Path Pair

[组合数取模-逆元计算模板] zoj 3624 Count Path Pair

思路:

正难则反

//C(M+N,M)*C(Q+M-P,Q)-C(N+M-P,N)*C(M+Q,M);

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"stack"
#include"algorithm"
#include"iostream"
using namespace std;
#define ll long long
#define mod 100000007
//C(M+N,M)*C(Q+M-P,Q)-C(N+M-P,N)*C(M+Q,M);
ll inverse[100005];

ll power(ll a,ll b)  //关于逆元 其实如果mod是素数 则b的逆元其实就是b^(mod-2)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ans;
}

ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    ll t,r=exgcd(b,a%b,x,y);
    t=x;
    x=y;
    y=t-a/b*y;
    return r;
}
ll get_inverse(ll a)       //exgcd求逆元
{
    ll x,y;
    exgcd(a,mod,x,y);
    return (x%mod+mod)%mod;
}
ll fc(ll n,ll m)
{
    /*ll t1,t2;                         //数据小的话直接乘起来最后求一次逆元快
    t1=t2=1;
    for(ll i=n;i>m;i--)
    {
        t1=(t1*i)%mod;
        t2=(t2*(i-m))%mod;
    }
    return t1*get_inverse(t2)%mod;*/

    ll ans=1;                          //如果数据比较大 先预处理会用到的逆元 然后每次都乘逆元
    for(ll i=n; i>m; i--)
    {
        ans=(ans*i)%mod;
        ans=(ans*inverse[i-m])%mod;
    }
    return ans;
}
int main()
{
    ll m,n,p,q;
    for(int i=1; i<=100000; i++) inverse[i]=power(i,mod-2); //预处理逆元
    for(int i=1; i<=100000; i++) inverse[i]=get_inverse(i); //预处理逆元
    while(scanf("%lld%lld%lld%lld",&m,&n,&p,&q)!=-1)
    {
        ll a,b,c,d,ans;
        a=fc(m+n,m);
        b=fc(q+m-p,q);
        c=fc(n+m-p,n);
        d=fc(m+q,m);
        ans=(a*b)%mod-(c*d)%mod;
        ans=(ans%mod+mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}


[组合数取模-逆元计算模板] zoj 3624 Count Path Pair