【ACM】2019湖北省省赛 D题 Catlan数

D. Dandelion

time limit per test

1.0 s

memory limit per test

256 MB

input

standard input

output

standard output

"O dandelion, yellow as gold,

What do you do all day?"

"I just wait here in the tall green grass

Till the children come to play."

"O dandelion, yellow as gold,

What do you do all night?"

"I wait and wait till the cool dews fall

And my hair grows long and white."

"And what do you do when your hair is white

And the children come to play?"

"They take me up in their dimpled hands

And blow my hair away!"

Spring is here and the dandelion is blooming. There is a small dandelion seed taking off. It will float upwards when there is no wind, and when the wind blows up it will be blown to the right.

In other words, if a dandelion seed is currently at point (x,y), the next second it will only appear in either point (x,y+1) or point (x+1,y). All points (x,y) on the path must satisfy the constraint that x is less than y(i.e x<y.

Now, there is a dandelion seed at point (0,0), please find the number of ways(mod 109+7109+7) to reach the point (m,n). 0<m<n≤1000000.

Input

The first line has a integer T (T<10), it means the number of the case.

The following lines of input will be two integers: m and n.

Output

For each case, print an integer in a single line to represent the answer.

 

Example

input

3
3 4
4 5
999 1000

output

5
14
894965608

题意就是求从(0,0)走到(x,y)(不经过y=x及其下方的部分)共有多少种方案。

没什么思路的时候就先打个表,打个表之后就可能有思路了。

这个题全面贯彻了这一句话~~~~

队友【此处插播一条广告】打了个1~10的表,我看着斜对角线上的数有点眼熟——Catlan数序列

猜想这题一定和这个数列有关,然而到结束也没做出来···

看了官方题解,它给出的是一个这样的公式:ans = C(n+m-1,m) - C(n+m-1,m-1) 确实和卡特兰数公式挺像的QAQ

但是我写代码的时候发现按照题解给的公式结果超级离谱(喷血)。

突发奇想把两项的符号反了一下,即ans = C(n+m-1,m-1) - C(n+m-1,m),结果正确,提交也AC了。

下面是我补题交的代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int mod=1e9+7;
const int maxn=200005;
long long jie[maxn];
long long power_mod(long long a, long long b)
{
    long long ans = 1;
    while (b)
    {
        if (b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
long long solve(long long n,long long m)
{
    long long qni=jie[n-m]*jie[m]%mod;
    long long ni=power_mod(qni%mod,mod-2)%mod;
    long long res=jie[n]*ni%mod;
    return res;
}
int main()
{
    //freopen("in.txt","r",stdin);
    jie[0]=1;
    for(int i=1; i<maxn; i++)
        jie[i]=jie[i-1]*i%mod;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        long long n,m;
        scanf("%lld%lld",&n,&m);
        //printf("%lld\n",solve(n+m-1,m-1));
        printf("%lld\n",(-solve(n+m-1,m)+solve(n+m-1,m-1)+mod)%mod);
    }
    return 0;
}

 为了解决这个问题,我掏出了书上的例题(组合数学 186页),原题是这样的:

书上的解题思路是这样的:

在这道题里套用这个思路,假设向上走为+1,向右走为-1.因为y必须大于x,所以第一步一定是向上走,序列最多是n+m-1项。

由于这道题中对角线上的元素是不满足题意的,所以序列和必须严格大于0,故公式里取m-1项时要比取m项时要大。

(公式的得出见组合数学 165页)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值