有一个无限大的矩形,初始时你在左上角(即第一行第一列),每次你都可以选择一个右下方格子,并瞬移过去(如从下图中的红色格子能直接瞬移到蓝色格子),求到第n行第m列的格子有几种方案,答案对1000000007取模。
多组测试数据。
两个整数n,m(2≤n,m≤100000)
一个整数表示答案
这个题目,初始是在左上角(1,1)的位置,最终要去(n,m)的位置,然后又只能往右下角走.所以这两个位置是钦定要走的.
所以相当于是在一个(n-2)(m-2)的地图往右下走,问有多少走走法
这时能走的步数最多为min(n-2,m-2),最少可以直接到达终点,一步都不在这个范围里面停留(指0步.
如果走0步,那么只有一种走法.
如果走1步,那么就有(n-2)(m-2)种走法.
如果走2步,那么就有C(2, m-2)*C(2, n-2)种
.
.
.
所以用一个循环,那这个每一种步数的所有方法数加起来.
求组合数(比如C(n,m))时,用到公式:
C(n,m) = m! / (n! * (n-m)!)
这里除法的时候,要使用逆元将除法转换成乘法(乘以一个数的逆元=除以一个数)
这里要用到费马小定理来求逆元,当p是素数时
a(p-1) = 1 (mod p)
1/a = a(p-2)
然后用快速幂求出a(p-2)
这样就能求出n!和(n-m)!的逆元
在预处理时先把1-100000的阶乘和逆元都算出来
然后再计算时可以直接
fac[m]inv[n]%MODinv[m-n]%MOD
然后就是答案了.
#include
#define MOD 1000000007
long n, m, min;
long long ans;
long long jc[100100], ni[100100];
long long mod_pow(long long x, long long n){
long long res = 1;
while(n > 0){
if(n & 1) res = res * x % MOD;
x = x * x % MOD;
n = n >> 1;
}
return res;
}
void init(){
jc[0] = 1;
for(int i = 1; i <= 100001; ++i){
jc[i] = jc[i-1]*i % MOD;
}
ni[0] = 1;
ni[100001] = mod_pow(jc[100001], MOD-2);
for(int i = 100000; i > 0; --i){
ni[i] = ni[i+1] * (i+1) % MOD;
}
}
long long c(long n, long m){
return jc[m] * ni[n] % MOD * ni[m-n] % MOD;
}
int main(){
init();
while(scanf("%ld%ld", &n, &m) != EOF){
n -= 2;
m -= 2;
min = (n>m)?m:n;
ans = 1;
for(int i = 1; i <= min; ++i){
ans = (ans + c(i,n) % MOD * c(i,m) % MOD) % MOD;
}
printf("%lld\n", ans);
}
}