题目描述
WYF正试图用一个栈来构造一棵树,现在他已经构造了n个元素作为树的节点,只要将这n个元素依次入栈出栈就可以形成一棵树了。当然,这个问题与树并没有关系,所以它叫做WYF的栈。每次你可以入栈一个新元素或者当栈非空时出栈一个元素,n个元素必须依次入栈,而WYF希望其中第m个元素入栈之后,栈中恰好有k个元素,现在他想知道一共有多少种入栈出栈顺序满足这个条件。
输入描述:
第一行一个正整数T,表示数据组数。(1<=T<=10000)
对于每组数据包含一行三个正整数n,m,k。
输出描述:
对于每组数据输出一个正整数表示答案。
由于答案可能过大,所以只需要输出对109+7取模后的答案
示例1
输入
2
3 3 3
3 3 2
输出
1
2
示例2
输入
5
10 3 2
10 2 2
10 7 5
10 6 2
10 7 6
输出
6864
11934
2200
3780
924
示例3
输入
2
5 4 4
5 2 1
输出
5
14
备注:
1<=n,m,k<=106
【题目链接】 link
题目描述
一天durong同学买了一个无限长的杯子,同时买了n个球,并且标号为1,2,3......n,durong同学突然想到一个问题----如果他把n个球依次,也就是按照1,2,3...n的顺序放进杯子里,然后在全部拿出来(注意不一定要等到全部放进去才能拿出球),并且会记录放进和拿出球的顺序,
durong想知道,要满足当第m个球进去后,杯子中此时恰好有k个球,然后仍然要把剩下的n-m个球放进去,最后杯中的球要取光,这样的放进和拿出球的顺序有多少种,答案有可能很大,所以mod上1e9+7
输入描述:
1<=n,m,k<=1e6(m可能大于n,k可能大于m)
第一行一个正整数T,表示数据组数。(1<=T<=10000)
对于每组数据包含一行三个正整数n,m,k。
输出描述:
对于每组数据输出一个正整数表示答案。
由于答案可能过大,所以只需要输出对1e9+7取模后的答案
示例1
输入
2
3 3 3
3 3 2
输出
1
2
【题目链接】 link
【思路】
这两道题目其实是一样的,就是求一个01序列满足:
- 一共有n个0,n个1需要进栈和出栈
- 对于所有的前缀,0的个数要大于等于1的个数
- 此题特殊要求:存在某个前缀满足刚好有m-1个0和m-k个1(因为第m个一定是0)
如果只有条件1,2,显然答案就是第n项卡特兰数。而根据条件2,3,我们可以反推到条件4,5
- 对于所有的后缀,1的个数要大于等于0的个数
- 存在某个后缀满足刚好有m-(m-k)个1和n-m个0
根据卡特兰数的结论,如果要满足某个前缀满足刚好有n个0和m个1,且所有前缀中0的个数均大于等于1的个数,则情况总数为C(n+m,n)-C(n+m,m-1)
那么情况总数就是2和3的方案数乘以4和5的方案数
#include <cstdio>
#include <bits/stdc++.h>
#include <cmath>
#include <map>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)
typedef long long ll;
const int maxn = 2000005;
const ll mod = 1e9+7;
const int INF = 1e9;
const double eps = 1e-6;
int n,m,k;
ll fac[maxn],inv[maxn];
ll fast_mod(ll a,ll n,ll Mod)
{
ll ans=1;
while(n)
{
if(n&1) ans=(ans*a)%Mod;
a=(a*a)%Mod;
n/=2;
}
return ans;
}
void init()
{
fac[0]=1;
for(int i=1;i<maxn;i++) fac[i]=(fac[i-1]*i)%mod;
inv[maxn-1]=fast_mod(fac[maxn-1],mod-2,mod);
for(int i=maxn-2;i>=0;i--) inv[i]=(inv[i+1]*(i+1))%mod;
}
ll C(int n,int m)
{
if(n<m) return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
ll cal(int n,int m)
{
return (C(n+m,n)-C(n+m,m-1)+mod)%mod;
}
int main()
{
init();
rush()
{
scanf("%d%d%d",&n,&m,&k);
if(m>n||k>m)
{
puts("0");
continue;
}
printf("%lld\n",cal(m-1,m-k)*cal(n-(m-k),n-m)%mod);
}
}