Dandelion(卡特兰数+费马小定理求逆元)

题目链接:http://whu2019.contest.codeforces.com/group/YyBKO8xFiH/contest/102167/problem/D

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+7) to reach the point (m,n). 0<m<n≤100000.

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: mm and nn.

Output

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

Example

input

Copy

3
3 4
4 5
999 1000

output

Copy

5
14
894965608

题意:求从(0,0)到(m,n)一共有多少种走法(要求:对于每一个坐标(x,y),x要小于y)

卡特兰数模板及典型应用https://blog.csdn.net/zuzhiang/article/details/77966726

本题考的是卡特兰数的一个变形,先看一个简单的问题

 n+m个人排队买票,并且满足,票价为50元,其中n个人各手持一张50元钞票,m个人各手持一张100元钞票,初始时候售票窗口没有钱,问有多少种排队的情况数能够让大家都买到票。

如果m=n的话那么这就是初始的Catalan数问题,也就是将手持50元的人看成是+1,手持100元的人看成是-1,任前k个数值的和都非负的序列数。

对于n>m的情况,假设大家都可以买到票的情况数是ans,无法让每个人都买到的情况数是cnt,那么就有ans+cnt=C(n+m,n),假设最早买不到票的人编号是k,他手持的是100元并且售票处没有钱,那么将前k个人的钱从50元变成100元,从100元变成50元,这时候就有n+1个人手持50元,m-1个手持100元的,所以就得到cnt=C(n+m,n+1),同时ans=C(n+m,n)-C(n+m,n+1)。

看完这个问题应该会有一点思路,甚至会觉得答案不就是C(n+m,n)-C(n+m,n+1)吗,但是通过这个式子算出来的结果和答案并不一样,为什么呢?

上面那个问题里的要求是对于每一个(x,y),要求x<=y,  但是本题的要求是x<y,那怎么办?

很容易想到,第一步只能是向上走(y+1),所以我们把第一步拿出来,只要后面每一个(x,y)满足x<=y,那么总的不就满足x<y了吗,题目也就转化成了求从(0,0)到(m,n-1)一共有多少种走法(要求:对于每一个坐标(x,y),x要小于等于y)

所以答案是ans = C(n+m-1,m) - C(n+m-1,m-1)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<list>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const int mod=1e9+7; 
ll ksm(ll a,ll b){
	ll s=1;
	while(b){
		if(b&1){
			a%=mod;
			s%=mod;
			s*=a;
		}
		a%=mod;
		a*=a;
		b>>=1;
	}
	return s%mod;
}
ll solve(ll n,ll m){ //c(n,m)
    if(m==0) return 1LL;
	if(m>n-m) m=n-m;
	ll a=1,b=1;//分子,分母
	for(int i=1;i<=m;i++){
		a=(a*(n-i+1))%mod;
		b=(b*i)%mod;
	}
	return a*ksm(b,mod-2)%mod;	
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
    	ll n,m;
    	scanf("%lld%lld",&m,&n);
    	printf("%lld\n",(solve(n+m-1,m)-solve(n+m-1,m-1)+mod)%mod);
	}
	return 0;
}



猜你喜欢

转载自blog.csdn.net/qq_42936517/article/details/89097699
今日推荐