题目描述
有 NNN 名士兵,身高各不相同,他们排成一排。
指挥官会任意选出三名士兵出列,其他士兵离开,只留下这三名士兵。
如果从左到右这三名士兵的身高顺序是 短、高、中(即最矮、最高、中等),那么指挥官会生气并惩罚他们。
其他任何顺序(如高、中、短;中、短、高等)都不会被惩罚。
士兵们不想被惩罚。
问:有多少种排列方式,使得无论选择哪三名士兵,他们从左到右的顺序 永远不会 出现“短、高、中”?
输入格式
第一行一个整数 TTT(1≤T≤5001 \le T \le 5001≤T≤500),表示测试用例数量。
接下来 TTT 行,每行一个整数 NNN(1≤N≤50001 \le N \le 50001≤N≤5000)。
输出格式
对于每个测试用例,输出满足条件的排列数,结果对 109+710^9+7109+7 取模。
样例输入
2
2
3
样例输出
2
5
问题分析
1. 问题重述
我们有 NNN 个不同的身高,不妨用 1,2,…,N1, 2, \dots, N1,2,…,N 表示,数值越小越矮。
一个排列 π\piπ 表示士兵从左到右的排列顺序。
任意选出三个位置 i<j<ki < j < ki<j<k,设这三个人的身高为 x=πix = \pi_ix=πi,y=πjy = \pi_jy=πj,z=πkz = \pi_kz=πk。
将这三个身高按数值从小到大排序,得到 a<b<ca < b < ca<b<c,分别对应“短”、“中”、“高”。
禁止的情况是:在原排列中,这三个人的出现顺序是 短、高、中,即:
- 最矮的人 aaa 在位置 iii
- 最高的人 ccc 在位置 jjj
- 中等的人 bbb 在位置 kkk
因为 a<b<ca < b < ca<b<c,所以 pi<pk<pjp_i < p_k < p_jpi<pk<pj。
2. 转换为模式避免问题
在排列模式避免(Pattern Avoidance\texttt{Pattern Avoidance}Pattern Avoidance)理论中,三个位置 i<j<ki < j < ki<j<k 满足 pi<pk<pjp_i < p_k < p_jpi<pk<pj 被称为 1−3−21-3-21−3−2 模式(也称为 132132132 模式)。
因此,本题等价于:求长度为 NNN 且不包含 132132132 模式的排列个数。
这是一个经典结论:避免 132132132 模式的排列数等于第 NNN 个卡特兰数(Catalan Number\texttt{Catalan Number}Catalan Number)。
解题思路
3. 卡特兰数简介
卡特兰数 CnC_nCn 的定义为:
C0=1,Cn+1=∑i=0nCi⋅Cn−i C_0 = 1, \quad C_{n+1} = \sum_{i=0}^{n} C_i \cdot C_{n-i} C0=1,Cn+1=i=0∑nCi⋅Cn−i
通项公式为:
Cn=1n+1(2nn) C_n = \frac{1}{n+1} \binom{2n}{n} Cn=n+11(n2n)
卡特兰数在很多组合问题中出现,例如:
- 合法括号序列数
- 二叉树形态数
- 凸多边形三角剖分数
- 不越过对角线的格路路径数
- 避免 132132132 模式的排列数
4. 为什么答案是卡特兰数?
这里给出一种直观理解(不严格证明,但有助于记忆):
考虑排列中最大值 NNN 的位置。如果最大值在位置 kkk,那么它左边有 k−1k-1k−1 个数,右边有 N−kN-kN−k 个数。
因为最大值不能出现在 132 模式中作为“高”的角色,实际上通过递推分析可以得到:
设 f(n)f(n)f(n) 为长度为 nnn 的合法排列数。考虑最大值的位置,其左边和右边的排列必须各自避免 132132132 模式,且右边所有数必须大于左边所有数(否则会出现 132132132 模式)。
这恰好满足卡特兰数的递推关系:
f(n)=∑i=0n−1f(i)⋅f(n−1−i) f(n) = \sum_{i=0}^{n-1} f(i) \cdot f(n-1-i) f(n)=i=0∑n−1f(i)⋅f(n−1−i)
与卡特兰数递推一致,且 f(0)=1f(0)=1f(0)=1,因此 f(n)=Cnf(n) = C_nf(n)=Cn。
5. 模运算与预处理
由于 N≤5000N \le 5000N≤5000,我们需要计算 CN=1N+1(2NN) mod MC_N = \frac{1}{N+1} \binom{2N}{N} \bmod MCN=N+11(N2N)modM,其中 M=109+7M = 10^9+7M=109+7。
- 预处理阶乘
fact[i] = i! mod M,最大到 2N2N2N。 - 预处理逆元
invFact[i],使用费马小定理 a−1≡aM−2(modM)a^{-1} \equiv a^{M-2} \pmod{M}a−1≡aM−2(modM)。 - 组合数 (2NN)=fact[2N]⋅invFact[N]⋅invFact[N] mod M\binom{2N}{N} = fact[2N] \cdot invFact[N] \cdot invFact[N] \bmod M(N2N)=fact[2N]⋅invFact[N]⋅invFact[N]modM。
- 最后乘以 N+1N+1N+1 的逆元。
时间复杂度 O(Nmax+T)O(N_{\max} + T)O(Nmax+T),空间复杂度 O(Nmax)O(N_{\max})O(Nmax)。
代码实现
// The Soldier's Dilemma
// UVa ID: 12887
// Verdict: Accepted
// Submission Date: 2026-05-27
// UVa Run Time: 0.000s
//
// 版权所有(C)2026,邱秋。metaphysis # yeah dot net
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1000000007;
const int MAXN = 5000;
long long fact[MAXN * 2 + 5], invFact[MAXN * 2 + 5];
long long modPow(long long a, long long e) {
long long res = 1;
while (e) {
if (e & 1) res = res * a % MOD;
a = a * a % MOD;
e >>= 1;
}
return res;
}
void precompute() {
fact[0] = 1;
for (int i = 1; i <= 2 * MAXN; ++i)
fact[i] = fact[i - 1] * i % MOD;
invFact[2 * MAXN] = modPow(fact[2 * MAXN], MOD - 2);
for (int i = 2 * MAXN - 1; i >= 0; --i)
invFact[i] = invFact[i + 1] * (i + 1) % MOD;
}
long long comb(int n, int k) {
if (k < 0 || k > n) return 0;
return fact[n] * invFact[k] % MOD * invFact[n - k] % MOD;
}
long long catalan(int n) {
return comb(2 * n, n) * modPow(n + 1, MOD - 2) % MOD;
}
int main() {
precompute();
int T;
scanf("%d", &T);
while (T--) {
int N;
scanf("%d", &N);
printf("%lld\n", catalan(N));
}
return 0;
}
总结
本题的关键在于将“短、高、中”这种身高顺序转化为排列中的 132132132 模式,然后利用组合数学中的经典结论:避免 132132132 模式的排列数等于卡特兰数。
通过预处理阶乘和逆元,可以在 O(1)O(1)O(1) 时间内回答每个测试用例,总时间复杂度 O(Nmax+T)O(N_{\max} + T)O(Nmax+T),空间复杂度 O(Nmax)O(N_{\max})O(Nmax),完全满足题目限制。
3747

被折叠的 条评论
为什么被折叠?



