結果
問題 | No.215 素数サイコロと合成数サイコロ (3-Hard) |
ユーザー | maine_honzuki |
提出日時 | 2020-12-23 00:00:08 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 1,730 ms / 4,000 ms |
コード長 | 8,025 bytes |
コンパイル時間 | 3,384 ms |
コンパイル使用メモリ | 230,572 KB |
実行使用メモリ | 12,416 KB |
最終ジャッジ日時 | 2024-09-21 14:24:38 |
合計ジャッジ時間 | 9,092 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1,719 ms
12,416 KB |
testcase_01 | AC | 1,730 ms
12,416 KB |
ソースコード
#include <bits/stdc++.h> using namespace std; using ll = long long; template <int mod> struct NumberTheoreticTransform { private: vector<int> rev, rts; int base, max_base, root; inline int mod_add(int a, int b) { a += b; if (a >= mod) a -= mod; return a; } inline int mod_mul(int a, int b) { return (int)((1ull * a * b) % (signed long long)mod); } inline int mod_pow(int a, int n) { int ret = 1; while (n) { if (n & 1) ret = mod_mul(ret, a); a = mod_mul(a, a); n >>= 1; } return ret; } inline int mod_inv(int a) { return mod_pow(a, mod - 2); } public: NumberTheoreticTransform() : rev{0, 1}, rts{0, 1}, base(1) { assert(mod >= 3 && (mod & 1) == 1); int tmp = mod - 1; max_base = 0; while (tmp % 2 == 0) { tmp >>= 1; max_base++; } root = 2; while (mod_pow(root, (mod - 1) >> 1) == 1) root++; assert(mod_pow(root, mod - 1) == 1); root = mod_pow(root, (mod - 1) >> max_base); } private: void ensure_base(int nbase) { if (nbase <= base) return; assert(nbase <= max_base); rev.resize(1 << nbase); rts.resize(1 << nbase); for (int i = 0; i < (1 << nbase); i++) { rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1)); } while (base < nbase) { int z = mod_pow(root, 1 << (max_base - 1 - base)); for (int i = 1 << (base - 1); i < (1 << base); i++) { rts[i << 1] = rts[i]; rts[(i << 1) + 1] = mod_mul(rts[i], z); } base++; } } void ntt(vector<int>& a) { const int n = (int)a.size(); assert((n & (n - 1)) == 0); int zeros = __builtin_ctz(n); ensure_base(zeros); int shift = base - zeros; for (int i = 0; i < n; i++) { if (i < (rev[i] >> shift)) swap(a[i], a[rev[i] >> shift]); } for (int k = 1; k < n; k <<= 1) { for (int i = 0; i < n; i += 2 * k) { for (int j = 0; j < k; j++) { int z = mod_mul(a[i + j + k], rts[j + k]); a[i + j + k] = mod_add(a[i + j], mod - z); a[i + j] = mod_add(a[i + j], z); } } } } public: vector<int> multiply(vector<int> a, vector<int> b) { if (a.empty() || b.empty()) return {}; bool eq = (a == b); int need = (int)(a.size() + b.size() - 1); int nbase = 1; while ((1 << nbase) < need) nbase++; ensure_base(nbase); int sz = 1 << nbase; a.resize(sz, 0); b.resize(sz, 0); ntt(a); if (eq) b = a; else ntt(b); int inv_sz = mod_inv(sz); for (int i = 0; i < sz; i++) { a[i] = mod_mul(a[i], mod_mul(b[i], inv_sz)); } reverse(a.begin() + 1, a.end()); ntt(a); a.resize(need); return a; } vector<long long> multiply(vector<long long> a, vector<long long> b) { vector<int> A(a.size()), B(b.size()); for (int i = 0; i < (int)a.size(); i++) { A[i] = (int)(a[i] % mod); } for (int i = 0; i < (int)b.size(); i++) { B[i] = (int)(b[i] % mod); } A = multiply(A, B); a.resize(A.size()); for (int i = 0; i < (int)A.size(); i++) a[i] = A[i]; return a; } }; template <typename T> T extgcd(T a, T b, T& x, T& y) { if (b) { T d = extgcd(b, a % b, y, x); y -= a / b * x; return d; } else { x = 1; y = 0; return a; } } template <typename T> T modinv(T a, T m) { T x, y; T d = extgcd(a, m, x, y); if (d != 1) return -1; x %= m; if (x < 0) x += m; return x; } template <typename T> T garner_mod(vector<T> r, vector<T> m, ll MOD) { assert(r.size() == m.size()); int N = (int)r.size(); vector<T> v(N); v[0] = r[0] % m[0]; for (int i = 1; i < N; i++) { T prod = 1; for (int j = 0; j < i; j++) { (prod *= m[j]) %= m[i]; } T tmp = v[i - 1]; for (int j = i - 2; j >= 0; j--) { tmp = (tmp * m[j] % m[i] + v[j]) % m[i]; } v[i] = (r[i] - tmp) * modinv(prod, m[i]) % m[i]; if (v[i] < 0) v[i] += m[i]; } T ret = 0; for (int i = N - 1; i >= 0; i--) { ret = (ret * m[i] % MOD + v[i]) % MOD; } return ret; } template <int mod> struct ArbitraryModConvolution { private: const int MOD0 = 167772161, MOD1 = 469762049, MOD2 = 754974721; NumberTheoreticTransform<167772161> NTT0; NumberTheoreticTransform<469762049> NTT1; NumberTheoreticTransform<754974721> NTT2; public: ArbitraryModConvolution() {} vector<ll> multiply(vector<ll> a, vector<ll> b) { if (a.empty() || b.empty()) return {}; auto V0 = NTT0.multiply(a, b), V1 = NTT1.multiply(a, b), V2 = NTT2.multiply(a, b); int N = (int)V0.size(); vector<ll> res(N); //vector<ll> v(3); //ll prod, tmp; for (int i = 0; i < N; i++) { vector<ll> r{V0[i], V1[i], V2[i]}, m{MOD0, MOD1, MOD2}; res[i] = garner_mod<ll>(r, m, mod); /* v[0] = V0[i] % MOD0; prod = MOD0 % MOD1; tmp = v[0]; v[1] = (V1[i] - tmp) * modinv<ll>(prod, MOD1) % MOD1; if (v[1] < 0) v[1] += MOD1; prod = ((MOD0 % MOD1) * MOD1) % MOD2; tmp = v[1]; tmp = (v[1] * MOD0 % MOD2 + v[0]) % MOD0; v[2] = (V2[i] - tmp) * modinv<ll>(prod, MOD2) % MOD2; if (v[2] < 0) v[2] += MOD2; res[i] = (res[i] * MOD2 % mod + v[2]) % mod; res[i] = (res[i] * MOD1 % mod + v[1]) % mod; res[i] = (res[i] * MOD0 % mod + v[0]) % mod; */ } return res; } }; template <class NTT> ll coef(vector<ll> P, vector<ll> Q, ll N, ll MOD) { //[x^N]P(x)/Q(x) //Q(0) = 1 NTT ntt; vector<ll> Qmin, V, U; while (N) { Qmin = Q; for (int i = 1; i < (int)Qmin.size(); i += 2) Qmin[i] = (MOD - Qmin[i]) % MOD; V = ntt.multiply(Q, Qmin); U = ntt.multiply(P, Qmin); P.clear(); Q.clear(); for (int i = 0; i < (int)V.size(); i += 2) { Q.emplace_back(V[i]); } if (N % 2 == 0) { for (int i = 0; i < (int)U.size(); i += 2) P.emplace_back(U[i]); } else { for (int i = 1; i < (int)U.size(); i += 2) P.emplace_back(U[i]); } N /= 2; } return P[0]; } int main() { ll N; int P, C; cin >> N >> P >> C; const int MOD = 1e9 + 7; vector<int> dice1{2, 3, 5, 7, 11, 13}, dice2{4, 6, 8, 9, 10, 12}; auto calc = [&MOD](vector<int> dice, int P) { int N = P * dice.back() + 1; vector<vector<ll>> dp(P + 1, vector<ll>(N)); dp[0][0] = 1; for (auto& x : dice) { for (int i = 0; i < P; i++) { for (int j = 0; j < N - x; j++) { (dp[i + 1][j + x] += dp[i][j]) %= MOD; } } } return dp[P]; }; using NTT = ArbitraryModConvolution<MOD>; NTT ntt; auto X = calc(dice1, P), Y = calc(dice2, C); auto Z = ntt.multiply(X, Y); vector<ll> T = Z; (T[0] += MOD - 1) %= MOD; for (auto& x : T) ((x *= -1) += MOD) %= MOD; vector<ll> S = Z; S[0] += 1; for (int i = (int)S.size() - 2; i >= 0; i--) (S[i] += S[i + 1]) %= MOD; S[0] = 0; cout << coef<NTT>(S, T, N, MOD) << endl; }