题意:有 n n n 个节点,按顺序入栈出栈,中间当第 m m m 个数入栈之后,要求栈内有 k k k 个元素,问一共这 n n n 个节点全部入栈完,再全部出栈,有多少种入栈出栈的顺序。
思路:我们可以设入栈为 0 0 0,出栈为 1 1 1,则满足题意的 01 01 01 串,前 m m m 长度的 01 01 01 串中, 1 1 1 比 0 0 0 要少 k k k 个,且每个前缀串的 0 0 0 的数量要不少于 1 1 1 的数量,由此转换成求卡特兰数。
卡特兰数:
满足递推式:
h
(
n
)
=
h
(
0
)
∗
h
(
n
−
1
)
+
h
(
1
)
∗
h
(
n
−
2
)
+
.
.
.
+
h
(
n
−
1
)
∗
h
(
0
)
(
n
>
=
2
)
h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)*h(0) (n>=2)
h(n)=h(0)∗h(n−1)+h(1)∗h(n−2)+...+h(n−1)∗h(0)(n>=2)
通项为:
h
(
n
)
=
C
2
n
n
(
n
+
1
)
h(n)=\frac{C_{2n}^n}{(n+1)}
h(n)=(n+1)C2nn
拓展到一般情况:
比如一个
01
01
01 串,要求有
n
n
n 个
1
1
1 ,
m
m
m 个
0
0
0,且每个前缀子串的
1
1
1 的个数要不小于
0
0
0 的个数,则这样的串的数量即为卡特兰数。
C
a
t
a
l
a
n
(
n
,
m
)
=
C
n
+
m
m
−
C
n
+
m
m
−
1
Catalan(n,m)=C_{n+m}^{m}-C_{n+m}^{m-1}
Catalan(n,m)=Cn+mm−Cn+mm−1(此情况为串中0代表元素相同,1代表元素相同)
C
a
t
a
l
a
n
(
n
,
m
)
=
(
C
n
+
m
m
−
C
n
+
m
m
−
1
)
∗
n
!
∗
m
!
Catalan(n,m)=(C_{n+m}^{m}-C_{n+m}^{m-1})*n!*m!
Catalan(n,m)=(Cn+mm−Cn+mm−1)∗n!∗m!(此情况为串中0代表元素各不相同,1代表元素各不相同)
#include<iostream>
#include<climits>
using namespace std;
#define mod 1000000007
int inv[2000005];
int mul[2000005];
int fac[2000005];
int c(int n, int m)
{
m = min(m, n - m);
if (m < 0)
return 0;
return (((((1LL * mul[n]) % mod) * fac[m]) % mod) * fac[n - m]) % mod;
}
int solve(int m, int n)
{
return (c(m + n, n) - c(m + n, n - 1) + mod) % mod;
}
int main()
{
int T;
int n, m, k;
mul[0] = inv[0] = mul[1] = inv[1] = fac[0] = fac[1] = 1;
for (int i = 2; i <= 2000000; ++i)
{
mul[i] = 1LL * mul[i - 1] * i % mod;
inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod;
fac[i] = 1LL * fac[i - 1] * inv[i] % mod;
}
cin >> T;
while(T--)
{
cin >> n >> m >> k;
cout << 1LL * solve(m - 1, m - k) * solve(n - m + k, n - m) % mod << '\n';
}
return 0;
}