mcpc2017 Hopscotch 组合数

5095: Hopscotch

题目描述

You’re playing hopscotch! You start at the origin and your goal is to hop to the lattice point (N, N). A hop consists of going from lattice point (x1, y1) to (x2, y2), where x1 < x2 and y1 < y2.
You dislike making small hops though. You’ve decided that for every hop you make between two lattice points, the x-coordinate must increase by at least X and the y-coordinate must increase by at least Y .
Compute the number of distinct paths you can take between (0, 0) and (N, N) that respect the above constraints. Two paths are distinct if there is some lattice point that you visit in one path which you don’t visit in the other.
Hint: The output involves arithmetic mod 109+ 7. Note that with p a prime like 109+ 7, and x an integer not equal to 0 mod p, then x(xp−2) mod p equals 1 mod p.

输入

The input consists of a line of three integers, N X Y . You may assume 1 ≤ X, Y ≤ N ≤ 106.

输出

The number of distinct paths you can take between the two lattice points can be very large. Hence output this number modulo 1 000 000 007 (109+ 7).

样例输入

7 2 3

样例输出

9

题目大意:给出n,x,y,从(0,0)到(n,n)  行坐标的增加每次不小于x,列坐标的增加每次不小于y。

题目分析:如果只看一维的可以把这个题看成把n个球分成t(1~n/x)份,每一份的个数都不能小于x,可以先向每一份分上x-1,就可以看成把剩下的分成t份有多少种分发,C(n-t*(x-1)-1  ,   t-1),这就是只看一维。

如果看成二维就是 : C(n-t*(x-1)-1 , t-1)*C(n-t*(y-1)-1 , t-1)。最后把所有结果加起来就可以。

还有一点要注意的是组合数不能直接求,要先打表,而且数很大,组合数求的时候要用到逆元。

#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e6+7; 
inline ll qpow(ll a,ll b){ll r=1,t=a; while(b){if(b&1)r=(r*t)%mod;b>>=1;t=(t*t)%mod;}return r;}

ll fac[maxn],inv[maxn];
 
ll init(){
    fac[0]=1;
    for (int i=1;i<maxn;i++)
        fac[i]=fac[i-1]*i%mod;
    inv[maxn-1]=qpow(fac[maxn-1],mod-2);
    for (int i=maxn-2;i>=0;i--)
        inv[i]=inv[i+1]*(i+1)%mod;
    return 0;
}
ll C(ll n,ll m){
    if (n<m) return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}

int main()
{
	ll n,x,y;
	init();
	scanf("%lld%lld%lld",&n,&x,&y);
	ll m=min(n/x,n/y);
	ll ans=0;
	for(ll i=1;i<=m;i++){
		ans=(ans+C(n-i*(x-1)-1,i-1)%mod*C(n-i*(y-1)-1,i-1)%mod)%mod;
	}
	printf("%lld\n",ans);
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值