##[$AcWing$ $1316$. 有趣的数列](https://www.acwing.com/problem/content/description/1318/) ### 一、题目描述 我们称一个长度为 $2n$ 的数列是有趣的,当且仅当该数列满足以下三个条件: - 它是从 $1$ 到 $2n$ 共 $2n$ 个整数的一个排列 ${a_i}$ - 所有的 **奇数项** 满足 $a_1 **解释**:联想一下嘉持老师的画二叉树,就是向左子树分配$i$个节点,那么向右子树就分配$n-i-1$个节点,因为根点了一个节点。 - ② 能挖掘出如下性质:任意前缀中,某种东西的数量 ≥ 另一种东西数量。 ![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202312041423367.png) ​ 组合数等于三个阶乘相乘除,因此我们求出各个阶乘的质因数分解,就能得到组合数的模$p$后大小。 ### 三、实现代码 ```cpp {.line-numbers} #include using namespace std; #define int long long #define endl "\n" const int N = 2000010; int n, mod; int primes[N], cnt; bool st[N]; void get_primes(int n) { for (int i = 2; i <= n; i++) { if (!st[i]) primes[cnt++] = i; for (int j = 0; primes[j] * i <= n; j++) { st[i * primes[j]] = true; if (i % primes[j] == 0) break; } } } int qmi(int a, int k) { int res = 1; while (k) { if (k & 1) res = res * a % mod; a = a * a % mod; k >>= 1; } return res; } int get(int n, int p) { int s = 0; while (n) { s += n / p; n /= p; } return s; } int C(int a, int b) { int res = 1; for (int i = 0; i < cnt; i++) { int p = primes[i]; int s = get(a, p) - get(b, p) - get(a - b, p); res = res * qmi(p, s) % mod; } return res; } signed main() { cin >> n >> mod; get_primes(n * 2); cout << (C(n * 2, n) - C(n * 2, n - 1) + mod) % mod << endl; } ```