public static void InitializeFactorial(long max, bool withInverse = false) { if (withInverse) { factorial_ = new ModInt[max + 1]; inverseFactorial_ = new ModInt[max + 1]; inverse_ = new ModInt[max + 1]; factorial_[0] = factorial_[1] = 1; inverseFactorial_[0] = inverseFactorial_[1] = 1; inverse_[1] = 1; for (int i = 2; i <= max; i++) { factorial_[i] = factorial_[i - 1] * i; inverse_[i] = p_ - inverse_[p_ % i] * (p_ / i); inverseFactorial_[i] = inverseFactorial_[i - 1] * inverse_[i]; } } else { factorial_ = new ModInt[max + 1]; inverseFactorial_ = new ModInt[max + 1]; factorial_[0] = factorial_[1] = 1; for (int i = 2; i <= max; i++) { factorial_[i] = factorial_[i - 1] * i; } inverseFactorial_[max] = new ModInt(1) / factorial_[max]; for (long i = max - 1; i >= 0; i--) { inverseFactorial_[i] = inverseFactorial_[i + 1] * (i + 1); } } }
public static Span <ModInt> Convolve(ReadOnlySpan <ModInt> a, ReadOnlySpan <ModInt> b) { int resultLength = a.Length + b.Length - 1; int nttLength = CeilPow2(resultLength); var aa = new ModInt[nttLength]; a.CopyTo(aa); var bb = new ModInt[nttLength]; b.CopyTo(bb); var fa = NumberTheoreticTransform(aa); var fb = NumberTheoreticTransform(bb); for (int i = 0; i < nttLength; ++i) { fa[i] *= fb[i]; } var convolved = NumberTheoreticTransform(fa, true); return(convolved.Slice(0, resultLength)); }
public static ModInt[,] NumberTheoreticTransform2D( ModInt[,] a, bool inverses = false, bool extends = false, bool inplaces = true) { int h = a.GetLength(0); int w = a.GetLength(1); if (extends) { h = CeilPow2(h); w = CeilPow2(w); inplaces = false; } var ret = a; if (inplaces == false) { ret = new ModInt[h, w]; int hh = a.GetLength(0); int ww = a.GetLength(1); for (int i = 0; i < hh; i++) { for (int j = 0; j < ww; j++) { ret[i, j] = a[i, j]; } } } if (h == 1 && w == 1) { return(ret); } var b = new ModInt[h, w]; { int n = w; int r = inverses ? (int)(ModInt.P - 1 - (ModInt.P - 1) / n) : (int)((ModInt.P - 1) / n); ModInt s = ModInt.Pow(ModInt.ROOT, r); var kp = new ModInt[n / 2 + 1]; kp.AsSpan().Fill(1); for (int i = 0; i < n / 2; ++i) { kp[i + 1] = kp[i] * s; } for (int y = 0; y < h; ++y) { int l = n / 2; for (int i = 1; i < n; i <<= 1, l >>= 1) { r = 0; for (int j = 0; j < l; ++j, r += i) { s = kp[i * j]; for (int k = 0; k < i; ++k) { var p = ret[y, k + r]; var q = ret[y, k + r + n / 2]; b[y, k + 2 * r] = p + q; b[y, k + 2 * r + i] = (p - q) * s; } } var temp = ret; ret = b; b = temp; } if (inverses) { s = ModInt.Inverse(n); for (int i = 0; i < n; ++i) { ret[y, i] = ret[y, i] * s; } } } } for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { b[i, j] = 0; } } { int n = h; int r = inverses ? (int)(ModInt.P - 1 - (ModInt.P - 1) / n) : (int)((ModInt.P - 1) / n); ModInt s = ModInt.Pow(ModInt.ROOT, r); var kp = new ModInt[n / 2 + 1]; kp.AsSpan().Fill(1); for (int i = 0; i < n / 2; ++i) { kp[i + 1] = kp[i] * s; } for (int x = 0; x < w; ++x) { int l = n / 2; for (int i = 1; i < n; i <<= 1, l >>= 1) { r = 0; for (int j = 0; j < l; ++j, r += i) { s = kp[i * j]; for (int k = 0; k < i; ++k) { var p = ret[k + r, x]; var q = ret[k + r + n / 2, x]; b[k + 2 * r, x] = p + q; b[k + 2 * r + i, x] = (p - q) * s; } } var temp = ret; ret = b; b = temp; } if (inverses) { s = ModInt.Inverse(n); for (int i = 0; i < n; ++i) { ret[i, x] = ret[i, x] * s; } } } } return(ret); }
public static Span <ModInt> NumberTheoreticTransform( Span <ModInt> a, bool inverses = false, bool extends = false, bool inplaces = true) { int n = a.Length; if (extends) { n = CeilPow2(n); inplaces = false; } var ret = a; if (inplaces == false) { ret = new ModInt[n]; a.CopyTo(ret); } if (n == 1) { return(ret); } var b = new ModInt[n].AsSpan(); int r = inverses ? (int)(ModInt.P - 1 - (ModInt.P - 1) / n) : (int)((ModInt.P - 1) / n); ModInt s = ModInt.Pow(ModInt.ROOT, r); var kp = new ModInt[n / 2 + 1]; kp.AsSpan().Fill(1); for (int i = 0; i < n / 2; ++i) { kp[i + 1] = kp[i] * s; } int l = n / 2; for (int i = 1; i < n; i <<= 1, l >>= 1) { r = 0; for (int j = 0; j < l; ++j, r += i) { s = kp[i * j]; for (int k = 0; k < i; ++k) { var p = ret[k + r]; var q = ret[k + r + n / 2]; b[k + 2 * r] = p + q; b[k + 2 * r + i] = (p - q) * s; } } var temp = ret; ret = b; b = temp; } if (inverses) { s = ModInt.Inverse(n); for (int i = 0; i < n; ++i) { ret[i] = ret[i] * s; } } return(ret); }