Kattis - hopscotch Hopscotc 组合数(逆元)

You’re playing hopscotch! You start at the origin and your goal is to hop to the lattice point (N,N)(N,N). A hop consists of going from lattice point (x1,y1)(x1,y1) to (x2,y2)(x2,y2), where x1<x2x1<x2 and y1<y2y1<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 XX and the y-coordinate must increase by at least YY.

Compute the number of distinct paths you can take between (0,0)(0,0) and (N,N)(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+7109+7. Note that with pp a prime like 109+7109+7, and xx an integer not equal to 00 mod pp, then x(xp−2)x(xp−2) mod pp equals 11 mod pp.

Input

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

Output

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+7109+7).

Sample Input 1 Sample Output 1
2 1 1
2
Sample Input 2 Sample Output 2
7 2 3
9

题意:给定n,x,y三个数字,从(0,0)加至少(x,y)到(n,n)的方法有多少种。(加法所加的数字的顺序不影响加法种类)

思路:x,y分开处理,最后算相同次数的乘积即可。n=a1+a2+....ai,所有的a项数肯定都大于x,所以将每一项都减去x-1,转化成为n-(x-1)*i=(a1-x+1)+(a2-x+1)+....+(ai-x+1),每一项肯定大于1,所以转化成为了n-(x-1)*i 个球 被i-1个板子隔开的问题(板子不可以重复放在同一个空隙和两边 可以画图看一下,刚开始个人没有理解为什么是i-1,询问队友画图后明白了,i-1板子隔开了才给到了i个人,我只是想到给i个人,没有考虑细节)

顺便附上组合数的模板模板思路

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

using namespace std;
typedef long long LL;
const LL maxn=1e6+5;
const LL mod=1e9+7;
LL Jc[maxn];
LL dp1[maxn];
LL dp2[maxn];
void calJc()    //求maxn以内的数的阶乘
{
    Jc[0] = Jc[1] = 1;
    for(LL i = 2; i < maxn; i++)
        Jc[i] = Jc[i - 1] * i % mod;
}
/*
//拓展欧几里得算法求逆元
void exgcd(LL a, LL b, LL &x, LL &y)    //拓展欧几里得算法
{
    if(!b) x = 1, y = 0;
    else
    {
        exgcd(b, a % b, y, x);
        y -= x * (a / b);
    }
}

LL niYuan(LL a, LL b)   //求a对b取模的逆元
{
    LL x, y;
    exgcd(a, b, x, y);
    return (x + b) % b;
}
*/

//费马小定理求逆元
LL pow(LL a, LL n, LL p)    //快速幂 a^n % p
{
    LL ans = 1;
    while(n)
    {
        if(n & 1) ans = ans * a % p;
        a = a * a % p;
        n >>= 1;
    }
    return ans;
}

LL niYuan(LL a, LL b)   //费马小定理求逆元
{
    return pow(a, b - 2, b);
}

LL C(LL a, LL b)    //计算C(a, b)
{
    return Jc[a] * niYuan(Jc[b], mod) % mod* niYuan(Jc[a - b], mod) % mod;
}
int main()
{
    LL n,x,y,ans=0;
    calJc();
    cin>>n>>x>>y;
    int len1=n/x,len2=n/y;
    for(int i=1;i<=len1;i++)
        dp1[i]=C(n-(x-1)*i-1,i-1)%mod;
    for(int i=1;i<=len2;i++)
        dp2[i]=C(n-(y-1)*i-1,i-1)%mod;
    int len=min(len1,len2);
    for(int i=1;i<=len;i++)
        ans=(ans+dp1[i]*dp2[i]%mod)%mod;
    cout<<ans<<endl;
    return 0;
}
扫描二维码关注公众号,回复: 2447864 查看本文章

猜你喜欢

转载自blog.csdn.net/deepseazbw/article/details/81196505
今日推荐