結果
| 問題 |
No.213 素数サイコロと合成数サイコロ (3-Easy)
|
| コンテスト | |
| ユーザー |
maine_honzuki
|
| 提出日時 | 2020-12-23 00:00:56 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 26 ms / 3,000 ms |
| コード長 | 8,025 bytes |
| コンパイル時間 | 3,423 ms |
| コンパイル使用メモリ | 223,564 KB |
| 最終ジャッジ日時 | 2025-01-17 06:15:52 |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 2 |
ソースコード
#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;
}
maine_honzuki