题面
解题思路
当
n
n
n是偶数是,答案是
n
!
n!
n!,当
n
n
n是奇数时,答案是
n
!
2
\frac{n!}{2}
2n!。
这里记录一份跑的很快的MTT和求
n
!
n!
n!的模板,给出来源博客链接。
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define fp(i,a,b) for(int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(int i=(a),I=(b)-1;i>I;--i)
typedef long long ll;
const int N = (1 << 17) + 5; int P;
int add(int x, int y) { return 0LL + x + y >= P ? 0LL + x + y - P : x + y; }
int dec(int x, int y) { return x < y ? x - y + P : x - y; }
int mul(int x, int y) { return 1LL * x * y - 1LL * x * y / P * P; }
int ksm(int x, int y) {
int res = 1;
for (; y; y >>= 1, x = mul(x, x)) (y & 1) ? res = mul(res, x) : 0;
return res;
}
const double Pi = acos(-1);
struct cp {
double x, y;
cp() {}
cp(double x, double y) :x(x), y(y) {}
cp operator + (const cp &b) const { return cp(x + b.x, y + b.y); }
cp operator - (const cp &b) const { return cp(x - b.x, y - b.y); }
cp operator * (const cp &b) const { return cp(x * b.x - y * b.y, x * b.y + y * b.x); }
cp operator * (const double &b) const { return cp(x * b, y * b); }
cp operator ~ () const { return cp(x, -y); }
}w[2][N];
int r[21][N], ifac[N], lg[N], inv[N]; double iv[21];
void Pre() {
iv[0] = 1;
for (int d = 1; d <= 17; d++) {
for (int i = 0; i < (1 << d); i++) r[d][i] = (r[d][i >> 1] >> 1) | ((i & 1) << (d - 1));
lg[1 << d] = d, iv[d] = iv[d - 1] * 0.5;
}
inv[0] = inv[1] = ifac[0] = ifac[1] = 1;
for (int i = 2; i <= 131072; i++) inv[i] = mul(P - P / i, inv[P % i]), ifac[i] = mul(ifac[i - 1], inv[i]);
for (int i = 1, d = 0; i < 131072; i <<= 1, d++) {
for (int k = 0; k < i; k++) {
w[1][i + k] = cp(cos(Pi * k * iv[d]), sin(Pi * k * iv[d]));
w[0][i + k] = cp(cos(Pi * k * iv[d]), -sin(Pi * k * iv[d]));
}
}
}
int lim, d;
void FFT(cp *A, int ty) {
for (int i = 0; i < lim; i++) if (i < r[d][i]) swap(A[i], A[r[d][i]]);
cp t;
for (int mid = 1; mid < lim; mid <<= 1) {
for (int j = 0; j < lim; j += (mid << 1)) {
for (int k = 0; k < mid; k++) {
A[j + k + mid] = A[j + k] - (t = w[ty][mid + k] * A[j + k + mid]);
A[j + k] = A[j + k] + t;
}
}
}
if (!ty) for (int i = 0; i < lim; i++) A[i] = A[i] * iv[d];
}
void MTT(int *a, int *b, int len, int *c) {
static cp f[N], g[N], p[N], q[N];
lim = len, d = lg[lim];
for (int i = 0; i < len; i++) f[i] = cp(a[i] >> 16, a[i] & 65535), g[i] = cp(b[i] >> 16, b[i] & 65535);
for (int i = len; i < lim; i++) f[i] = g[i] = cp(0, 0);
FFT(f, 1); FFT(g, 1);
for (int i = 0; i < lim; i++) {
cp t, f0, f1, g0, g1;
t = ~f[i ? lim - i : 0], f0 = (f[i] - t) * cp(0, -0.5), f1 = (f[i] + t) * 0.5;
t = ~g[i ? lim - i : 0], g0 = (g[i] - t) * cp(0, -0.5), g1 = (g[i] + t) * 0.5;
p[i] = f1 * g1, q[i] = f1 * g0 + f0 * g1 + f0 * g0 * cp(0, 1);
}
FFT(p, 0); FFT(q, 0);
for (int i = 0; i < lim; i++)
c[i] = (((ll(p[i].x + 0.5) % P << 16) % P << 16)
+ (ll(q[i].x + 0.5) << 16)
+ ll(q[i].y + 0.5)) % P;
}
void calc(int *a, int *b, int n, int k) {
static int f[N], g[N], h[N], sum[N], isum[N];
int len = 1; while (len <= n + n) len <<= 1;
for (int i = 0; i <= n; i++) f[i] = mul(a[i], mul(ifac[i], ifac[n - i]));
for (int i = n - 1; i >= 0; i -= 2) f[i] = P - f[i];
int t = dec(k, n);
for (int i = 0; i <= n * 2; i++) g[i] = add(i, t);
sum[0] = g[0];
for (int i = 1; i <= n * 2; i++) sum[i] = mul(sum[i - 1], g[i]);
isum[n * 2] = ksm(sum[n * 2], P - 2);
for (int i = n * 2; i >= 1; i--) isum[i - 1] = mul(isum[i], g[i]);
for (int i = 1; i <= n * 2; i++) g[i] = mul(isum[i], sum[i - 1]);
g[0] = isum[0];
for (int i = n + 1; i < len; i++) f[i] = 0;
for (int i = n * 2 + 1; i < len; i++) g[i] = 0;
MTT(f, g, len, h);
int res = 1, p1 = k - n, p2 = k;
for (int i = p1; i <= p2; i++) res = 1LL * res * i % P;
res = dec(res, 0);
for (int i = 0; i <= n; i++) g[i] = (0LL + P + p1 + i) % P;
sum[0] = g[0];
for (int i = 1; i <= n; i++) sum[i] = mul(sum[i - 1], g[i]);
isum[n] = ksm(sum[n], P - 2);
for (int i = n; i >= 1; i--) isum[i - 1] = mul(isum[i], g[i]);
for (int i = 1; i <= n; i++) g[i] = mul(isum[i], sum[i - 1]);
g[0] = isum[0];
for (int i = 0; i <= n; p2 = add(p2, 1), ++i)
b[i] = mul(h[i + n], res), res = mul(res, mul(g[i], p2 + 1));
}
int solve(int b1) {
static int a[N], b[N], c[N];
int s = 0;
for (int p = b1; p; p >>= 1) ++s;
a[0] = 1, --s;
int qwq = ksm(b1, P - 2);
for (int p = 0; s >= 0; --s) {
if (p) {
calc(a, b, p, p + 1);
for (int i = 0; i < p; i++) a[p + i + 1] = b[i];
a[p << 1 | 1] = 0;
calc(a, b, p << 1, mul(p, qwq));
p <<= 1;
for (int i = 0; i <= p; i++) a[i] = mul(a[i], b[i]);
}
if (b1 >> s & 1) {
for (int i = 0; i <= p; i++) a[i] = mul(a[i], (1LL * b1 * i + p + 1) % P);
p |= 1, a[p] = 1;
for (int i = 1; i <= p; i++) a[p] = mul(a[p], (1LL * b1 * p + i) % P);
}
}
int res = 1;
for (int i = 0; i < b1; i++) res = mul(res, a[i]);
return res;
}
int GetFac(int n) {
int s = sqrt(n), res = solve(s);
for (int i = s * s + 1; i <= n; i++) res = mul(res, i);
return res;
}
int Fac(int n) {
if (n > P - 1 - n) {
int res = ksm(GetFac(P - 1 - n), P - 2);
return (P - 1 - n) & 1 ? res : P - res;
}
return GetFac(n);
}
int n;
int main() {
//freopen("0.txt", "r", stdin);
scanf("%d%d", &n, &P); Pre();
int ans = Fac(n);
if (n % 2) ans = mul(ans, ksm(2, P - 2));
printf("%d\n", ans);
return 0;
}