51nod 1627 瞬间移动(组合数学)

传送门

解题思路

  因为每次横纵坐标至少(+1),所以可以枚举走的步数,枚举走的步数(i)后剩下的就是把(n-1)(m-1)划分成(i)个有序正整数相加,所以用隔板法,(ans=sumlimits_{i=1}^{min(n,m)-1} C(n-2,i-1)*C(m-2,i-1))

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
const int MAXN = 100005;
const int MOD = 1e9+7;
typedef long long LL;

int n,m,fac[MAXN],inv[MAXN];
LL ans;

int fast_pow(int x,int y){
	int ret=1;
	for(;y;y>>=1){
		if(y&1) ret=(LL)ret*x%MOD;
		x=(LL)x*x%MOD;	
	}	
	return ret;
}

inline LL C(int x,int y){
	if(x<y) return 0;	
	return (LL)fac[x]*inv[y]%MOD*inv[x-y]%MOD;
}

int main(){
	scanf("%d%d",&n,&m);int Max=max(n,m),Min=n+m-Max;fac[0]=1;
	for(int i=1;i<=Max;i++) fac[i]=(LL)fac[i-1]*i%MOD;
	inv[Max]=fast_pow(fac[Max],MOD-2);
	for(int i=Max-1;~i;i--) inv[i]=(LL)inv[i+1]*(i+1)%MOD;
	for(int i=1;i<Min;i++) ans=(ans+(LL)C(n-2,i-1)*C(m-2,i-1)%MOD)%MOD;
	printf("%lld
",ans);
	return 0;	
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/10062031.html