51nod-1119 1119 机器人走方格 V2(组合数学+乘法逆元+快速幂)
题目链接:
基准时间限制:1 秒
空间限制:131072 KB
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的思想是这样的,dp[i][j]=dp[i-1][j]+dp[i][j-1];这种是i,j分别表示i行j列;
我们来转换一下,p[x][j表示第x-j行第j列的方案数,那么p和dp之间的关系是什么样的呢?
p[i][j]=dp[i-j-1][j]+dp[i-j][j-1]=p[i-1][j]+p[i-1][j-1];
即p[i][j]=p[i-1][j]+p[i-1][j-1];诶?这个东西好熟悉啊啊啊;让我想想在哪见过......
哈哈哈哈,这就是组合数的递推公式啊,Ci,j=Ci-1,j+Ci-1,j-1;
所以答案就是Cn+m-2,n;
然后就是求乘法逆元和快速幂了;
AC代码:
#include <bits/stdc++.h> using namespace std; const int N=1e6+5; typedef long long ll; const ll mod=1e9+7; ll dp[2*N]; void Iint() { dp[1]=1; for(int i=2;i<=200000;i++) { dp[i]=(dp[i-1]*(ll)i)%mod; } } ll n,m; ll fast_pow(ll a,ll b)//快速幂; { ll s=1,base=a; while(b) { if(b&1) { s*=base; s%=mod; } base *= base; base%=mod; b=(b>>1); } return s; } int main() { Iint(); while(scanf("%lld%lld",&n,&m)!=EOF) { n--; m--; ll x=dp[n]*dp[m]%mod; ll ans=dp[n+m]*fast_pow(x,mod-2)%mod; printf("%lld\n",ans); } return 0; }