// 在线性筛中,如果 i 这个数是被第 k 个质数筛掉的,那么 sieveBy[i] = k // prs[i] 表示第 i 个质数
for (int i = n + 2; i <= 2 * n; ++i) { // 加上分子 n + 2 到 2n 的乘积的分解 int x = i; while (x > 1) { // 分解质因数 ++f[sieveBy[x]]; x = x / prs[sieveBy[x]]; } } for (int i = 2; i <= n; ++i) { // 消去分母中 1 到 n 的乘积的分解 int x = i; while (x > 1) { --f[sieveBy[x]]; x = x / prs[sieveBy[x]]; } }
bool notprime[2000000 + 10]; int prs[2000000 + 10], cnt; int sieveBy[2000000 + 10]; int n, p; int calcs[2000000 + 10];
intfastPow(int a, int b, int p){ int ret = 1; while (b) { if (b & 1) ret = 1ll * ret * 1ll * a % p; a = 1ll * a * 1ll * a % p; b >>= 1; } return ret; }
voidsieve(){ notprime[0] = notprime[1] = true; for (int i = 2; i <= 2 * n; ++i) { if (!notprime[i]) { prs[++cnt] = i; sieveBy[i] = cnt; } for (int j = 1; j <= cnt && i * prs[j] <= 2 * n; ++j) { notprime[i * prs[j]] = true; sieveBy[i * prs[j]] = j; } } }
intmain(){ scanf("%d %d", &n, &p); sieve(); // ans = ((2n)! / (n! * n!) * (n + 1)) // = ((1 * 2 * ... * (n - 1) * n * (n + 1) * (n + 2) * (n + 3) * ... * 2n) / // (1 * 2 * ... * (n - 1) * n) * (1 * 2 * ... * (n - 1) * n) * (n + 1)) // = ((n + 1) * (n + 2) * (n + 3) * ... * 2n) / // ((1 * 2 * ... * (n - 1) * n) * (n + 1)) // = ((n + 2) * (n + 3) * ... * 2n) / ((1 * 2 * ... * (n - 1) * n) for (int i = n + 2; i <= 2 * n; ++i) { int x = i; while (x > 1) { // printf("Now exting: %d\n", x); ++calcs[sieveBy[x]]; x = x / prs[sieveBy[x]]; } } // printf("Calc 1.\n"); for (int i = 2; i <= n; ++i) { int x = i; while (x > 1) { --calcs[sieveBy[x]]; x = x / prs[sieveBy[x]]; } } int ans = 1; for (int i = 1; i <= cnt; ++i) { ans = 1ll * ans * 1ll * fastPow(prs[i], calcs[i], p) % p; } printf("%d\n", ans); return0; }