Submission #727413

#TimeUsernameProblemLanguageResultExecution timeMemory
727413model_codeFestivals in JOI Kingdom 2 (JOI23_festival2)C++17
100 / 100
6239 ms3980 KiB
#include<bits/stdc++.h> #define rep(i, n) for (ll i = 0; i < ll(n); ++i) #define rep2(i, s, n) for (ll i = ll(s); i < ll(n); ++i) #define rrep(i, n) for (ll i = ll(n) - 1; i >= 0; i--) #define SZ(a) int(a.size()) using namespace std; using ll = long long; class mint { ll x; static int mod; public: static void set_mod(int _mod) { mod = _mod; } mint(ll x = 0) : x((x % mod + mod) % mod) { assert(mod > 0); } constexpr int val() const { return x; } mint &operator+=(const mint &a) { if ((x += a.val()) >= mod) x -= mod; return *this; } mint &operator-=(const mint &a) { if ((x += mod - a.val()) >= mod) x -= mod; return *this; } mint &operator*=(const mint &a) { (x *= a.val()) %= mod; return *this; } mint operator+(const mint &a) const { mint res(*this); return res += a; } mint operator-(const mint &a) const { mint res(*this); return res -= a; } mint operator*(const mint &a) const { mint res(*this); return res *= a; } mint pow(ll t) const { mint res = 1, a(*this); while (t > 0) { if (t & 1) res *= a; t >>= 1; a *= a; } return res; } mint inv() const { return pow(mod - 2); } }; int mint::mod = 0; using vm = vector<mint>; vm karatsuba(const vm &f, const vm &g) { int n = SZ(f); int m = SZ(g); if (!n or !m) return {}; if (min(n, m) <= 40) { vm res(n + m - 1); rep(i, n) rep(j, m) res[i + j] += f[i] * g[j]; return res; } int a = max(n, m) / 2; vm f0(f.begin(), f.begin() + min(a, n)); vm f1(f.begin() + min(a, n), f.end()); vm g0(g.begin(), g.begin() + min(a, m)); vm g1(g.begin() + min(a, m), g.end()); vm h0 = karatsuba(f0, g0); vm h2 = karatsuba(f1, g1); vm h1; { vm df(max(SZ(f0), SZ(f1))); rep(i, SZ(f0)) df[i] += f0[i]; rep(i, SZ(f1)) df[i] -= f1[i]; vm dg(max(SZ(g0), SZ(g1))); rep(i, SZ(g0)) dg[i] -= g0[i]; rep(i, SZ(g1)) dg[i] += g1[i]; h1 = karatsuba(df, dg); } if (SZ(h1) < max(SZ(h0), SZ(h2))) h1.resize(max(SZ(h0), SZ(h2))); rep(i, SZ(h0)) h1[i] += h0[i]; rep(i, SZ(h2)) h1[i] += h2[i]; vm res(n + m - 1); rep(i, SZ(h0)) res[i] += h0[i]; rep(i, SZ(h1)) res[i + a] += h1[i]; rep(i, SZ(h2)) res[i + a * 2] += h2[i]; return res; } int main() { int n, p; cin >> n >> p; mint::set_mod(p); vm fact(2 * n + 10, 1); vm ifact(2 * n + 10); rep2(i, 1, SZ(fact)) fact[i] = fact[i - 1] * i; ifact.back() = fact.back().inv(); rrep(i, SZ(fact) - 1) ifact[i] = ifact[i + 1] * (i + 1); // A : 正しい貪欲で選ぶ区間の集合 B : 嘘貪欲で選ぶ区間の集合 // |A| = |B| のものを数える // A, B に含まれる区間を後ろから 1 çµ„ãšã¤åŠ ãˆã¦ã„ã (é–“ã«ã‚ã‚‹åŒºé–“ã‚‚åŒæ™‚ã«åŠ ãˆã‚‹) // dp[i][j] // i : åŠ ãˆãŸåŒºé–“ã®å€‹æ•° // j : A, B ã«å«ã¾ã‚Œã‚‹åŒºé–“ã®ã†ã¡æœ€å¾Œã«åŠ ãˆãŸçµ„ãŒåˆ¥ã€…ã®åŒºé–“ã‹ã©ã†ã‹ vector dp(n + 1, vm(2)); dp[1][0] = 1; if (n >= 2) dp[2][1] = 1; // O(N^2) での DP (subtask 5) // rep2(i, 1, n + 1) { // // 0 -> 0 // if (i + 1 <= n) { // mint now = dp[i][0]; // rep(j, n - i) { // dp[i + 1 + j][0] += now; // now *= 2 * i - 1 + j; // } // } // // 0 -> 1 // if (i + 2 <= n) { // mint now = dp[i][0]; // rep(j, n - i - 1) { // dp[i + 2 + j][1] += now * (j + 1); // now *= 2 * i - 1 + j; // } // } // // 1 -> 0 // if (i + 1 <= n) { // mint now = dp[i][1]; // rep(j, n - i) { // dp[i + 1 + j][0] += now * (j + 1); // now *= 2 * i - 2 + j; // } // } // // 1 -> 1 // if (i + 2 <= n) { // mint now = dp[i][1]; // rep(j, n - i - 1) { // dp[i + 2 + j][1] += now * (j + 2) * (j + 1); // now *= 2 * i - 2 + j; // } // } // } // O(N^1.59) での DP (満点解) // [l, m) から [m, r) への遷移をまとめて行う auto induce = [&](int l, int m, int r) -> void { vm f(m - l), g(r - l - 1); // 0 -> 0 { rep2(i, l, m) f[m - 1 - i] = dp[i][0] * ifact[2 * i - 2]; rep2(i, l + m, m + r - 1) g[i - (l + m)] = fact[i - 3]; vm h = karatsuba(f, g); rep2(i, m, r) dp[i][0] += h[m - l - 1 + i - m]; } // 0 -> 1 if (m - l >= 2) { rep2(i, l, m - 1) f[m - 1 - i] = dp[i][0] * ifact[2 * i - 2]; f[0] = 0; rep2(i, l + m, m + r - 1) g[i - (l + m)] = fact[i - 4]; vm h = karatsuba(f, g); rep2(i, m, r) dp[i][1] += h[m - l - 1 + i - m] * (i - 1); rep2(i, l, m - 1) f[m - 1 - i] *= -i; h = karatsuba(f, g); rep2(i, m, r) dp[i][1] += h[m - l - 1 + i - m]; } { int i = m - 1; rep2(j, m + 1, r) { dp[j][1] += dp[i][0] * (j - i - 1) * fact[i + j - 4] * ifact[2 * i - 2]; } } // 1 -> 0 { rep2(i, l, m) f[m - 1 - i] = dp[i][1] * (i >= 2 ? ifact[2 * i - 3] : 0); rep2(i, l + m, m + r - 1) g[i - (l + m)] = (i >= 4 ? fact[i - 4] : 0); vm h = karatsuba(f, g); rep2(i, m, r) dp[i][0] += h[m - l - 1 + i - m] * i; rep2(i, l, m) f[m - 1 - i] *= -i; h = karatsuba(f, g); rep2(i, m, r) dp[i][0] += h[m - l - 1 + i - m]; } // 1 -> 1 if (m - l >= 2) { rep2(i, l, m - 1) f[m - 1 - i] = dp[i][1] * (i >= 2 ? ifact[2 * i - 3] : 0); f[0] = 0; rep2(i, l + m, m + r - 1) g[i - (l + m)] = (i >= 5 ? fact[i - 5] : 0); vm h = karatsuba(f, g); rep2(i, m, r) dp[i][1] += h[m - l - 1 + i - m] * i * (i - 1); rep2(i, l, m - 1) f[m - 1 - i] *= i; h = karatsuba(f, g); rep2(i, m, r) dp[i][1] += h[m - l - 1 + i - m] * (-2 * i); rep2(i, l, m - 1) f[m - 1 - i] *= i + 1; h = karatsuba(f, g); rep2(i, m, r) dp[i][1] += h[m - l - 1 + i - m]; } { int i = m - 1; rep2(j, m + 1, r) { dp[j][1] += dp[i][1] * (j * (j - 1) - 2 * i * j + i * (i + 1)) * fact[i + j - 5] * ifact[2 * i - 3]; } } }; auto solve = [&](auto &solve, int l, int r) -> void { assert(l < r); if (r - l == 1) return; int m = (l + r) / 2; solve(solve, l, m); induce(l, m, r); solve(solve, m, r); }; solve(solve, 1, n + 1); mint ans = 1; rep(i, n) ans *= 2 * i + 1; rep2(i, 1, n + 1) { ans -= dp[i][0] * fact[n + i - 2] * ifact[2 * i - 2]; if (i >= 2) ans -= dp[i][1] * (n - i + 1) * fact[n + i - 3] * ifact[2 * i - 3]; } cout << ans.val() << endl; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...