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
相关问题
一开始我的做法十分的傻逼,就是用dp递推,这个方法只适用于n,m的数值都小于1000 当有1e6的时候,用这个方法就是找死(自己也没看范围),如果范围小就是棋盘DP,范围大就要用到小费马定理。
首先,他的方法数是有规律可寻,规律看如下(每行每列的方案数):
1 1 1 1 1
1 2 3 4 5
1 3 6 10 15
1 4 10 20 35
即可变成
C(0,1) C(0,2) C(0,3) C(0,4) C(0,5)
C(1,1)C(1,2) C(1,3) C(1,4) C(1,5)
C(2,2) C(2,3) C(2,4) C(2,5) C(2,6)
C(3,3) C(3,4) C(3,5) C(3,6) C(3,7)
方案数变成了C(n-1,n+m-2)===>(n+m-2)!/((n-1)!(m+1)!)
因为n,m,mod太大,一般求法会爆,所以用了小费马定理(也可以用卢卡斯定理)
小费马定理是 当对任意m有不是mod的倍数的数b,有b^(m-1)=1(mod m)
∴b*b^(m-2)=1 ∴a/b==>a*b^(m-2)
b^(m-1)就是b的逆元了
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 2000000
#define mod 1000000007
long long int J[N];
void init(){
int i;
memset(J,0,sizeof(J));
J[1]=1;
for(i=2;i<=2000000;i++){
J[i]%=mod;
J[i]=(J[i-1]*i)%mod;
J[i]%=mod;
}
return ;
}
long long int mi(long long int n,long long int m){
long long int base=n,r=1;
while(m){
if(m&1)
r=(r*base)%mod;
base=(base*base)%mod;
m>>=1;
}
return r;
}
int main()
{
long long int i,j,n,m;
scanf("%lld %lld",&n,&m);
init();
long long int ans=J[m+n-2];
ans=(ans*mi(J[n-1],mod-2))%mod;
ans=(ans*mi(J[m-1],mod-2))%mod;
printf("%lld\n",ans);
return 0;
}