51nod:1118 机器人走方格(排列组合+逆元)

1118 机器人走方格
基准时间限制:1 秒 空间限制:131072 KB 分值: 0  难度:基础题
 收藏
 关注
M * N的方格,一个机器人从左上走到右下,只能向右或向下走。有多少种不同的走法?由于方法数量可能很大,只需要输出Mod 10^9 + 7的结果。
Input
第1行,2个数M,N,中间用空格隔开。(2 <= m,n <= 1000)
Output
输出走法的数量。
Input示例
2 3
Output示例
3
解题思路:从最左一边走到最右一边,需要走n-1步,从最上边走到最下边,需要走m-1步,所以一共走n+m-2步。这n+m-2步中,有些步是向右的,有些步是向下的,将这些步排列组合ans=c(n+m-2,n-1)或ans=c(n+m-2,m-1)。
这样,在组合公式中除法不能直接取模,那么求逆元即可。
求逆元:1.a的逆元=(a^(p-2))modp;
2.a的逆元用exgcd求解。
代码如下:
方法一(对应逆元求法1):
#include 
#define LL long long
const LL M=1000000007;
LL quick_pow(LL a,LL b)
{
	LL t=1;
	LL base=a;
	while(b)
	{
		if(b&1)
		{
			t=(t*base)%M;
		}
		b=(b>>1);
		base=(base*base)%M;
	}
	return t%M;
}
LL calc(LL n,LL m)
{
	LL tmp1=1,tmp2=1;
	for(LL i=n-m+1;i<=n;i++)
	{
		tmp1=(tmp1*i)%M;
	}
	for(LL i=1;i<=m;i++)
	{
		tmp2=(tmp2*i)%M;
	}
	return (tmp1*quick_pow(tmp2,M-2))%M;
}
int main()
{
	LL m,n;
	scanf("%lld%lld",&m,&n);
	printf("%lld\n",calc(m+n-2,n-1));
	return 0;
 } 

代码2:
#include 
void exgcd(long long a,long long b,long long &x,long long &y)
{
	if(b==0)
	{
		x=1;
		y=0;
		return ;
	}
	exgcd(b,a%b,x,y);
	long long tmp=x;
	x=y;
	y=tmp-(a/b)*y;
}
long long calc(long long n,long long m)
{
	long long tmp1=1,tmp2=1;
	for(long long i=n-m+1;i<=n;i++)
	{
		tmp1=(tmp1*i)%1000000007;
	}
	for(long long i=1;i<=m;i++)
	{
		tmp2=(tmp2*i)%1000000007;
	}
	long long x,y;
	exgcd(tmp2,1000000007,x,y);
	long long ni=x;
	while(ni<0)
	{
		ni=(ni+1000000007)%1000000007;
	}
	return (tmp1*ni)%1000000007;
}
int main()
{
	long long n,m;
	scanf("%lld%lld",&m,&n);
	printf("%lld\n",calc(m+n-2,n-1));
	return 0;
 } 


你可能感兴趣的:(逆元,exgcd,排列组合)