51Nod1119 - 机器人走方格 V2 - 排列组合推公式+逆元+快速幂
题面
\(M\) x \(N\) 的方格,一个机器人从左上走到右下,只能向右或向下走。有多少种不同的走法?由于方法数量可能很大,只需要输出Mod 10^9 + 7的结果。
思路
如果给出的数据较小,可以直接DP写(详情见https://www.cnblogs.com/OFSHK/p/13817688.html),
但是本题的数据过大,连dp的数组都无法开,所以我们要想办法转化一下。
在\(m\) x \(n\) 的图中,我们需要从从 \(m+n\) 步中选出 \(m\) 步向下走或 \(n\) 步向右走,所以总共有 \(C(m+n,m)=C(m+n,n)\) 种组合数(也就是路线
数)。
转化成题目给我们的就是 \(C(m-1+n-1, m-1)\) \(=\) \(\frac{(m-1+n-1)!}{(m-1)! \times (n-1)!}\) \(=\) \(\frac{(m+n-2)!}{(m-1)! \times (n-1)!}\) 。
然后针对其中的阶乘,主函数开始的时候预处理一下就行,涉及到逆元的直接利用快速幂求解即可。
求组合数(取模)的两种方法:https://www.zybuluo.com/ArrowLLL/note/713749
AC代码
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
const ll mod=1e9+7;
int m,n;
ll a[2000010];
ll ksm(ll x,int nn) // **快速幂写错了
{
ll res=1;
while(nn)
{
if(nn&1)
res=res*x%mod;
x=x*x%mod;
nn>>=1;
}
return res;
}
int main()
{
cin>>n>>m;
a[1]=1;
for(int i=2;i<=n+m-2;i++)
a[i]=(a[i-1]*i)%mod; // 阶乘
ll x=a[n+m-2],y=a[n-1]*a[m-1]%mod;
cout<<x*ksm(y,mod-2)%mod<<endl;
return 0;
}