HDU

来源:互联网 发布:python 图像分割提取 编辑:程序博客网 时间:2024/05/16 01:46

有一个无限大的矩形,初始时你在左上角(即第一行第一列),每次你都可以选择一个右下方格子,并瞬移过去(如从下图中的红色格子能直接瞬移到蓝色格子),求到第n行第m列的格子有几种方案,答案对1000000007取模。 

Input
多组测试数据。 

两个整数n,m(2≤n,m≤100000) 
Output
一个整数表示答案

Sample Input

4 5
Sample Output
10

没推出公式,看题解都说是杨辉三角:求C(n-2+m-2,m-2),

从一个点可以往右下走,从起点(1,1)到终点(n,m)的方案数,可以分解为需要经过几个中间点的问题,由于可到达的中间点为矩阵(2,2)~(n-1,m-1)内的点,可取的中间点个数为0,1,……min(n-2,m-2),那么找i个中间点其实就是找i个行i个列,其方案数分别为C(m-2,i)*C(n-2,i), i=0到n-2∑C(i,m-2)*C(i,n-2))=C(n-2,m+n-4).

那么组合数求余用Lucas定理,由于求组合数是涉及除法求余,还要用到除法求逆元,即用到公式b^(p-2)==(1/b) (mod p)

代码:

#include<iostream>#include<string>#include<cstdio>#include<algorithm>#include<cmath>#include<iomanip>#include<queue>#include<cstring>#include<map>using namespace std;typedef long long ll;#define M 15#define mod 1000000007ll pow_mod(ll n,ll k){    ll res=1;    while(k>0)    {        if(k&1)            res=res*n%mod;        n=n*n%mod;        k>>=1;    }    return res;}ll C(ll n,ll m){    if(n<m)        return 0;    ll ans=1;    for(ll i=1;i<=m;i++)    {        ll a=n-m+i;        ll b=i;        //本来有ans=ans*(a/b),但是除法不满足取余,利用b^(p-2)==(1/b) (mod p)        ans=ans*(a*pow_mod(b,mod-2)%mod)%mod;    }    return ans;}ll Lucas(ll n,ll m){    if(m==0)        return 1;    return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod;}int main(){    ll n,m;    while(scanf("%lld%lld",&n,&m)!=EOF)    {        ll a=m+n-4;        ll b=min(m-2,n-2);        printf("%lld\n",Lucas(a,b));    }    return 0;}

推理参考:http://blog.csdn.net/queuelovestack/article/details/51476288,

https://www.zybang.com/question/c01c6717d750636e7499faff8288ec36.html

除法求逆元(扩展欧几里德和费马小定理)