【组合数学】bzoj3260跳

题面

邪教喜欢在各种各样空间内跳。

现在,邪教来到了一个二维平面。在这个平面内,如果邪教当前跳到了(x,y),那么他下一步可以选择跳到以下4个点:(x-1,y), (x+1,y), (x,y-1), (x,y+1)。

而每当邪教到达一个点,他需要耗费一些体力,假设到达(x,y)需要耗费的体力用C(x,y)表示。

对于C(x,y),有以下几个性质:

1、若x=0或者y=0,则C(x,y)=1。

2、若x>0且y>0,则C(x,y)=C(x,y-1)+C(x-1,y)。

3、若x<0且y<0,则C(x,y)=无穷大。

现在,邪教想知道从(0,0)出发到(N,M),最少花费多少体力(到达(0,0)点花费的体力也需要被算入)。

由于答案可能很大,只需要输出答案对10^9+7取模的结果。

输入

读入两个整数N,M,表示邪教想到达的点。

输出

输出仅一个整数,表示邪教需要花费的最小体力对10^9+7取模的结果。

样例输入

1 2

样例输出

6

提示 【数据说明】 对于10%的数据,满足N, M<=20; 对于30%的数据,满足N, M<=100; 对于60%的数据,满足min(N,M)<=100; 对于100%的数据,满足0<=N, M<=10^12,N*M<=10^12。

解答

把整个表格顺时针旋转45度就会发现这是一个杨辉三角。于是乎我们不妨设$n>m$,那么就有答案为: \(N+\sum C_{N+i}^{i}\) 有因为有如下推论 \(\sum\limits_{i=0}^MC_{N+i}^{i} = C_{M+N+1}^{M}\) 然后就可以直接计算了 代码:

# include <iostream>
# include <cstdio>
using namespace std;
const long long mod = (int)1e9+7;
long long fp(long long b,long long p){
	int ans = 1;
	while(p){
		if(p&1)ans = ans*b%mod;
		b = b*b%mod;
		p>>=1;
	}
	return ans;
}
long long n,m;
int main(){
	scanf("%lld%lld",&n,&m);
	if(n<m)swap(n,m);
	n%=mod;
	long long ans = 1,ansb = 1;
	for(long long i = 1;i<=m;i++){
		ans = ans * ((n+m+2-i+mod)%mod)%mod;
		ansb = ansb*i%mod;
	}
	ans = ((ans*fp(ansb,mod-2)%mod+n)%mod+mod)%mod;
	printf("%lld",ans);
	return 0;
}