HDU 5698 瞬间移动 (2016"百度之星" - 初赛(Astar Round2B) 1003)

传送门
瞬间移动

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 140 Accepted Submission(s): 66

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

Input
多组测试数据。

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

Output
一个整数表示答案

Sample Input
4 5

Sample Output
10

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

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

C(m+n4,n+2)=(n+m4)!(n2)!(m2)!

因为这个数要对MOD取余,那么我们需要求一下(n-2)!*(m-2)!关于MOD的逆元,这个其实一个循环就行,每次扩展欧几里得一下,就OK了,最后就是编码了,
第一步:写一个扩展欧几里得算法,求a关于b的逆元;
第二步:根据公式,一步步的求,先求(n+m-4)!模上MOD,然后再for循环求两个阶乘的逆元
第三步:输出结果。

上代码:

#include <iostream>
using namespace std;
typedef long long LL;
const LL MOD = 1000000007;
void exgcd(LL a, LL b, LL &x, LL &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return;
    }
    LL x1, y1;
    exgcd(b, a%b, x1, y1);
    x = y1;
    y = x1-(a/b)*y1;
}
int main()
{
    LL n, m;
    while(cin>>n>>m)
    {
        LL ans = 1;
        for(LL i=1; i<=n+m-4; i++)
            ans = (ans*i)%MOD;
        for(LL i=1; i<=n-2; i++)
        {
            LL x, y;
            exgcd(i, MOD, x, y);
            x = (x%MOD+MOD)%MOD;
            ans = (ans*x)%MOD;
        }
        for(LL i=1; i<=m-2; i++)
        {
             LL x, y;
            exgcd(i, MOD, x, y);
            x = (x%MOD+MOD)%MOD;
            ans = (ans*x)%MOD;
        }
        ans = (ans%MOD+MOD)%MOD;
        cout<<ans<<endl;
    }
    return 0;
}

你可能感兴趣的:(组合数学)