This documentation is automatically generated by online-judge-tools/verification-helper
#include "FPS/incseqcount.hpp"
#pragma once #include "Math/comb.hpp" template <typename T> T NumberofIncreasingSequencesBetweenTwoSequences(int n, vector<int> a, vector<int> b) { auto step = [&](int n, vector<int> a, vector<T> &init) -> vector<T> { auto rec = [&](auto &self, int L, int R, vector<T> &dp) -> vector<T> { assert(SZ(dp) == R - L); if (R - L == 1) { vector<T> ret(a[L], dp[0]); return ret; } int mid = (L + R) >> 1; int offset = a[mid - 1]; vector<T> Ldp = {dp.begin(), dp.begin() + mid - L}; vector<T> Lret = self(self, L, mid, Ldp); int sz = a[R - 1]; vector<T> ret(sz); vector<T> Rdp(R - mid); if (offset == 0) { rep(i, 0, R - mid) Rdp[i] = dp[i + mid - L]; } else { { Poly<T> X(offset), Y(R - mid + offset); rep(j, 0, offset) X[j] = Lret[j] * Fact<T>(offset - 1 - j, 1); rep(k, 0, R - mid + offset) Y[k] = Fact<T>(k); X *= Y; rep(i, 0, R - mid) Rdp[i] += X[i + offset - 1] * Fact<T>(i, 1); } { Poly<T> X(offset), Y(offset); rep(j, 0, offset) X[j] = Lret[j]; rep(k, 0, offset) Y[k] = nCr<T>(R - mid - 1 + k, k); X *= Y; rep(i, 0, offset) ret[i] += X[i]; } { Poly<T> X(R - mid), Y(R - mid); rep(j, 0, R - mid) X[j] = dp[j + mid - L]; rep(j, 0, R - mid) Y[j] = nCr<T>(j + offset - 1, j); X *= Y; rep(i, 0, R - mid) Rdp[i] += X[i]; } { Poly<T> X(R - mid), Y(offset + R - mid); rep(j, 0, R - mid) X[j] = dp[j + mid - L] * Fact<T>(R - mid - 1 - j, 1); rep(k, 0, offset + R - mid) Y[k] = Fact<T>(k); X *= Y; rep(i, 0, offset) ret[i] += X[R - mid - 1 + i] * Fact<T>(i, 1); } } rep(j, mid, R) a[j] -= offset; vector<T> Rret = self(self, mid, R, Rdp); rep(j, offset, sz) ret[j] = Rret[j - offset]; return ret; }; auto ret = rec(rec, 0, n, init); rrep(j, 0, SZ(ret) - 1) ret[j + 1] -= ret[j]; return ret; }; rep(i, 0, n - 1) chmax(a[i + 1], a[i]); rrep(i, 0, n - 1) chmin(b[i], b[i + 1]); rep(i, 0, n) if (a[i] >= b[i]) { return 0; } int offset = a.front(); for (auto &x : a) x -= offset; for (auto &x : b) x -= offset + 1; a.insert(a.begin(), 0); b.push_back(b.back()); bool vert = 1; vector<T> dp(b[0] + 1); dp[0] = 1; int x = 0, y = 0; for (;;) { if (x == n and y == b.back()) break; if (vert) { // up vector<int> H; for (;;) { int add = UB(a, y) - x; H.push_back(add); if (y == b[x]) break; y++; } assert(SZ(dp) == SZ(H)); auto nxt = step(SZ(H), H, dp); swap(dp, nxt); } else { // right vector<int> H; for (;;) { int add = b[x] - y + 1; H.push_back(add); if (x == n or y < a[x + 1]) break; x++; } assert(SZ(dp) == SZ(H)); auto nxt = step(SZ(H), H, dp); swap(dp, nxt); } vert ^= 1; } return accumulate(ALL(dp), T(0)); } /** * @brief Number of Increasing Sequences Between Two Sequences */
#line 2 "Math/comb.hpp" template <typename T> T Inv(ll n) { static int md; static vector<T> buf({0, 1}); if (md != T::get_mod()) { md = T::get_mod(); buf = vector<T>({0, 1}); } assert(n > 0); n %= md; while (SZ(buf) <= n) { int k = SZ(buf), q = (md + k - 1) / k; buf.push_back(buf[k * q - md] * q); } return buf[n]; } template <typename T> T Fact(ll n, bool inv = 0) { static int md; static vector<T> buf({1, 1}), ibuf({1, 1}); if (md != T::get_mod()) { md = T::get_mod(); buf = ibuf = vector<T>({1, 1}); } assert(n >= 0 and n < md); while (SZ(buf) <= n) { buf.push_back(buf.back() * SZ(buf)); ibuf.push_back(ibuf.back() * Inv<T>(SZ(ibuf))); } return inv ? ibuf[n] : buf[n]; } template <typename T> T nPr(int n, int r, bool inv = 0) { if (n < 0 || n < r || r < 0) return 0; return Fact<T>(n, inv) * Fact<T>(n - r, inv ^ 1); } template <typename T> T nCr(int n, int r, bool inv = 0) { if (n < 0 || n < r || r < 0) return 0; return Fact<T>(n, inv) * Fact<T>(r, inv ^ 1) * Fact<T>(n - r, inv ^ 1); } // sum = n, r tuples template <typename T> T nHr(int n, int r, bool inv = 0) { return nCr<T>(n + r - 1, r - 1, inv); } // sum = n, a nonzero tuples and b tuples template <typename T> T choose(int n, int a, int b) { if (n == 0) return !a; return nCr<T>(n + b - 1, a + b - 1); } /** * @brief Combination */ #line 3 "FPS/incseqcount.hpp" template <typename T> T NumberofIncreasingSequencesBetweenTwoSequences(int n, vector<int> a, vector<int> b) { auto step = [&](int n, vector<int> a, vector<T> &init) -> vector<T> { auto rec = [&](auto &self, int L, int R, vector<T> &dp) -> vector<T> { assert(SZ(dp) == R - L); if (R - L == 1) { vector<T> ret(a[L], dp[0]); return ret; } int mid = (L + R) >> 1; int offset = a[mid - 1]; vector<T> Ldp = {dp.begin(), dp.begin() + mid - L}; vector<T> Lret = self(self, L, mid, Ldp); int sz = a[R - 1]; vector<T> ret(sz); vector<T> Rdp(R - mid); if (offset == 0) { rep(i, 0, R - mid) Rdp[i] = dp[i + mid - L]; } else { { Poly<T> X(offset), Y(R - mid + offset); rep(j, 0, offset) X[j] = Lret[j] * Fact<T>(offset - 1 - j, 1); rep(k, 0, R - mid + offset) Y[k] = Fact<T>(k); X *= Y; rep(i, 0, R - mid) Rdp[i] += X[i + offset - 1] * Fact<T>(i, 1); } { Poly<T> X(offset), Y(offset); rep(j, 0, offset) X[j] = Lret[j]; rep(k, 0, offset) Y[k] = nCr<T>(R - mid - 1 + k, k); X *= Y; rep(i, 0, offset) ret[i] += X[i]; } { Poly<T> X(R - mid), Y(R - mid); rep(j, 0, R - mid) X[j] = dp[j + mid - L]; rep(j, 0, R - mid) Y[j] = nCr<T>(j + offset - 1, j); X *= Y; rep(i, 0, R - mid) Rdp[i] += X[i]; } { Poly<T> X(R - mid), Y(offset + R - mid); rep(j, 0, R - mid) X[j] = dp[j + mid - L] * Fact<T>(R - mid - 1 - j, 1); rep(k, 0, offset + R - mid) Y[k] = Fact<T>(k); X *= Y; rep(i, 0, offset) ret[i] += X[R - mid - 1 + i] * Fact<T>(i, 1); } } rep(j, mid, R) a[j] -= offset; vector<T> Rret = self(self, mid, R, Rdp); rep(j, offset, sz) ret[j] = Rret[j - offset]; return ret; }; auto ret = rec(rec, 0, n, init); rrep(j, 0, SZ(ret) - 1) ret[j + 1] -= ret[j]; return ret; }; rep(i, 0, n - 1) chmax(a[i + 1], a[i]); rrep(i, 0, n - 1) chmin(b[i], b[i + 1]); rep(i, 0, n) if (a[i] >= b[i]) { return 0; } int offset = a.front(); for (auto &x : a) x -= offset; for (auto &x : b) x -= offset + 1; a.insert(a.begin(), 0); b.push_back(b.back()); bool vert = 1; vector<T> dp(b[0] + 1); dp[0] = 1; int x = 0, y = 0; for (;;) { if (x == n and y == b.back()) break; if (vert) { // up vector<int> H; for (;;) { int add = UB(a, y) - x; H.push_back(add); if (y == b[x]) break; y++; } assert(SZ(dp) == SZ(H)); auto nxt = step(SZ(H), H, dp); swap(dp, nxt); } else { // right vector<int> H; for (;;) { int add = b[x] - y + 1; H.push_back(add); if (x == n or y < a[x + 1]) break; x++; } assert(SZ(dp) == SZ(H)); auto nxt = step(SZ(H), H, dp); swap(dp, nxt); } vert ^= 1; } return accumulate(ALL(dp), T(0)); } /** * @brief Number of Increasing Sequences Between Two Sequences */