前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Gym 100947E】Qwerty78 Trip(组合数取模/费马小定理)

【Gym 100947E】Qwerty78 Trip(组合数取模/费马小定理)

作者头像
饶文津
发布2020-06-02 15:33:53
4400
发布2020-06-02 15:33:53
举报
文章被收录于专栏:饶文津的专栏饶文津的专栏

从(1,1)到(n,m),每次向右或向下走一步,,不能经过(x,y),求走的方案数取模。 可以经过(x,y)则相当于m+n步里面选n步必须向下走,方案数为

C((m−1)+(n−1),n−1)

再考虑其中经过(x,y)的方案数,也就是(1,1)到(x,y)的方案乘上(x,y)到(n,m)的方案,为

C((x−1)+(y−1),x−1)×C((n−x)+(m−y),n−x)

于是答案就是下式取模

C(m+n−2,n−1)−C(x+y−2,x−1)×C(n−x+m−y,n−x)

m和n大到10的五次方,而组合数要用除法,所以要用费马小定理来求逆元。简单的说就是

C(n,m)%M=n!%M×(m!)−1%M×[(n−m)!]−1%M

而逆元用费马小定理和快速幂来算

(m!)−1=qpow(m!,M−2)

最后减法取模记得要再加M再取一次模。

代码语言:javascript
复制
#include<bits/stdc++.h>
#define N 200005
#define M 1000000007
#define ll long long
using namespace std;
ll n,m,t,x,y,fac[N]= {1};
ll qpow(ll a,ll b)
{
    ll ans=1;
    ll k=a;
    while(b)
    {
        if(b&1)ans=ans*k%M;
        k=k*k%M;
        b>>=1;
    }
    return ans;
}
ll C(ll n,ll m)
{
    if(m>n)return 0;
    return fac[n]*qpow(fac[m],M-2)%M*qpow(fac[n-m],M-2)%M;
}
int main()
{
    for(int i=1; i<N; i++)fac[i]=fac[i-1]*i%M;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d%d",&n,&m,&x,&y);
        printf("%lld\n",((C(n+m-2,n-1)-C(x+y-2,x-1)*C(n-x+m-y,n-x)%M+M)%M));
    }
    return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-07-06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档