1119 机器人走方格V2
M * N的方格,一个机器人从左上走到右下,只能向右或向下走。有多少种不同的走法?由于方法数量可能很大,只需要输出Mod 10^9 + 7的结果。
Input
第1行,2个数M,N,中间用空格隔开。(2 <= m,n <= 1000000)
Output
输出走法的数量 Mod 10^9 + 7。
Input示例
2 3
Output示例
3
题解:
这道题用到的主要是一些数学知识。
组合数学:可以求出这道题的答案是C(m+n-2, m-1)(一共需要走n+m-2步,从中选出m-1步向下走的就是结果)。
离散数学:C(m+n-2, m-1)= (n+m-2)!/((n-1)!(m-1)!),涉及到除法取模的问题。定义运算为模1e9+9乘,那么(a/b)%mod = (a*b-1)%mod = (a%mod(b-1)%mod)%mod.所以只需要计算分母在该运算下的逆元即可。
费马小定理:对于一个素数M,如果gcd(p, m)= 1.那么有p^(M-1)% mod = 1,那么p的逆元就是p^(M-2)(这里的1e9+9是素数可以直接用费马小定理,否则应当找一个比题中mod大的素数求完结果在取一次模),这样就可以求解逆元问题(快速幂)。
一些细节问题详见代码实现。
代码:
#include<iostream>
#include<cstring>
#include<math.h>
#include<stdlib.h>
#include<cstring>
#include<cstdio>
#include<utility>
#include<algorithm>
#include<map>
#include<stack>
using namespace std;
typedef long long ll;
const int Max = 2*1e6+5;
const int mod = 1e9+7;//是素数
const int Hash = 10000;
const int INF = 1<<30;
const ll llINF = 1e18;
int m,n;
ll arr[Max];
void init( )
{
arr[0] = 1;
for(ll i=1; i<Max; i++)
arr[i] = (i*arr[i-1])%mod;
}
ll inverse(ll y)//费马小定理求y的逆元
{
int n = mod-2;
ll temp = 1;
while( n/2 )
{
if(n % 2)
temp = (temp*y)%mod;
y = (y*y)%mod;
n /= 2;
}
return (y*temp)%mod;
}
int main( )
{
//freopen("input.txt", "r", stdin);
init( );//预处理出来1百万以内的阶乘结果
while(~scanf("%d%d",&m, &n))
{
ll x = arr[n+m-2];//分子
ll y = (arr[m-1]*arr[n-1])%mod;//分母
ll y_ = inverse( y );//求y的乘模逆元
ll ans = (x*y_)%mod;//代数系统的性质
cout<<ans<<endl;
}
return 0;
}