hdu 5698(组合数加卢卡斯定理)

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

Input

多组测试数据。

两个整数n,m(2≤n,m≤100000)

Output

一个整数表示答案

Sample Input

 

4 5

Sample Output

 

10

Source

2016"百度之星" - 初赛(Astar Round2B)

Recommend

wange2014   |   We have carefully selected several similar problems for you:  6396 6395 6394 6393 6392 

首先我们分析一下这个题其实就是我们要从(1, 1)点走到(n, m)点,而且只能走右下方,那么我们就相当于从(n+m-4)个格子里选n-2(或者是m-2)个格子,因为我们得去掉n-1行和m-1列(这个不能选),然后再去掉第一行和第一列,所以就是

C(m+n−4,n+2)=(n+m−4)!(n−2)!∗(m−2)!

卢卡斯定理对大数取模

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define ll long long
const ll p=1e9+7;
ll multi(ll a,ll b,ll m)
{
    ll ans=0;
    a%=m;
    while(b)
    {
        if(b&1)
        {
            ans=(ans+a)%m;
            b--;
        }
        b>>=1;
        a=(a+a)%m;
    }
    return ans;
}
ll quick_mod(ll a,ll b,ll m)
{
    ll ans=1;
    a%=m;
    while(b)
    {
        if(b&1)
        {
            ans=multi(ans,a,m);
            b--;
        }
        b>>=1;
        a=multi(a,a,m);
    }
    return ans;
}
ll getc(ll n,ll m)
{
    if(n<m)
    return 0;
    if(m>n-m);
    m=n-m;
    ll s1=1,s2=1;
    for(ll i=0;i<m;i++)

    {
        s1=s1*(n-i)%p;
        s2=s2*(i+1)%p;
    }
    return s1*quick_mod(s2,p-2,p);
}
ll lucas(ll n,ll m)
{
    if(m==0)
    return 1;
    return getc(n%p,m%p)*lucas(n/p,m/p)%p;
}
int main()
{
    ll n, m;
    while(~scanf("%lld%lld",&n,&m))
    {
     printf("%lld\n",lucas(n+m-4,n-2));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sdauguanweihong/article/details/81662410