[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=1485
[算法]
我们不妨从1-2N依次选取奇数项
考虑到P2n-1 < P2n , 显然 , 当1至i中 , 不选的数 > 选了的数 , 不合法
那么 , 当一个序列满足 : 1-i中 , 不选的数 > 选了的数 , 则这个序列是“有趣”的
可以把该问题转化为一个经典模型 : 满足前i位0的个数 <= 1的个数的长度为2N的二进制数有多少个 , 答案为卡特兰数的第n项
卡特兰数的通项公式 : Cn = C(2n , n) - C(2n , n - 1)
由于答案对P取模 , 而P不是质数 , 逆元可能不存在 , 我们需要在求组合数时求出每个质因子在阶乘中出现了多少次 , 然后快速幂计算答案即可
时间复杂度 : O(NlogN)
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXN 1000010 #define MAXP 2000010 int n , P , tot; int f[MAXP] , prime[MAXP] , a[MAXP] , b[MAXP] , loc[MAXP]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline int exp_mod(int a , int n) { int res = 1 , b = a; while (n > 0) { if (n & 1) res = 1LL * res * b % P; b = 1LL * b * b % P; n >>= 1; } return res; } inline int C(int x , int y) { for (int i = 1; i <= tot; i++) a[i] = 0; for (int k = 1; k <= x; k++) { int tmp = k; for (int i = 1; i <= tot && 1LL * prime[i] * prime[i] <= k; i++) { if (tmp % prime[i] == 0) { while (tmp % prime[i] == 0) { tmp /= prime[i]; ++a[i]; } } if (tmp == 1 || loc[tmp]) break; } if (tmp > 1) { int pos = loc[tmp]; ++a[pos]; } } for (int k = 1; k <= y; k++) { int tmp = k; for (int i = 1; i <= tot && 1LL * prime[i] * prime[i] <= k; i++) { if (tmp % prime[i] == 0) { while (tmp % prime[i] == 0) { tmp /= prime[i]; --a[i]; } } if (tmp == 1 || loc[tmp]) break; } if (tmp > 1) { int pos = loc[tmp]; --a[pos]; } } for (int k = 1; k <= x - y; k++) { int tmp = k; for (int i = 1; i <= tot && 1LL * prime[i] * prime[i] <= k; i++) { if (tmp % prime[i] == 0) { while (tmp % prime[i] == 0) { tmp /= prime[i]; --a[i]; } } if (tmp == 1 || loc[tmp]) break; } if (tmp > 1) { int pos = loc[tmp]; --a[pos]; } } int ans = 1; for (int i = 1; i <= tot; i++) ans = 1LL * ans * exp_mod(prime[i] , a[i]) % P; return ans; } int main() { read(n); read(P); for (int i = 2; i < MAXP; i++) { if (!f[i]) { f[i] = i; prime[++tot] = i; loc[i] = tot; } for (int j = 1; j <= tot; j++) { int tmp = i * prime[j]; if (tmp >= MAXP) break; f[tmp] = prime[j]; if (prime[j] == f[i]) break; } } printf("%d " , (C(2 * n , n) - C(2 * n , n - 1) + P) % P); return 0; }