結果
問題 |
No.3127 Multiple of Twin Prime
|
ユーザー |
![]() |
提出日時 | 2025-04-25 21:56:26 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 113 ms / 2,500 ms |
コード長 | 21,516 bytes |
コンパイル時間 | 4,206 ms |
コンパイル使用メモリ | 303,728 KB |
実行使用メモリ | 10,420 KB |
最終ジャッジ日時 | 2025-04-25 21:56:43 |
合計ジャッジ時間 | 7,081 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 12 |
ソースコード
#include <bits/stdc++.h> #include <cassert> using namespace std; using ll = long long int; using u64 = unsigned long long; using pll = pair<ll, ll>; // #include <atcoder/all> // using namespace atcoder; #define REP(i, a, b) for (ll i = (a); i < (b); i++) #define REPrev(i, a, b) for (ll i = (a); i >= (b); i--) #define ALL(coll) (coll).begin(), (coll).end() #define SIZE(v) ((ll)((v).size())) #define REPOUT(i, a, b, exp, sep) REP(i, (a), (b)) cout << (exp) << (i + 1 == (b) ? "" : (sep)); cout << "\n" // @@ !! LIM(sieve) // ---- inserted library file algOp.cc // Common definitions // zero, one, inverse template<typename T> const T zero(const T& t) { if constexpr (is_integral_v<T> || is_floating_point_v<T>) { return (T)0; } else { return t.zero(); } } template<typename T> const T one(const T& t) { if constexpr (is_integral_v<T> || is_floating_point_v<T>) { return (T)1; } else { return t.one(); } } template<typename T> const T inverse(const T& t) { if constexpr (is_floating_point_v<T>) { return 1.0 / t; } else { return t.inverse(); } } #ifdef BOOST_MP_CPP_INT_HPP template<> const cpp_int zero(const cpp_int& t) { return cpp_int(0); } template<> const cpp_int one(const cpp_int& t) { return cpp_int(1); } #endif // BOOST_MP_CPP_INT_HPP // begin -- detection ideom // cf. https://blog.tartanllama.xyz/detection-idiom/ namespace tartan_detail { template <template <class...> class Trait, class Enabler, class... Args> struct is_detected : false_type{}; template <template <class...> class Trait, class... Args> struct is_detected<Trait, void_t<Trait<Args...>>, Args...> : true_type{}; } template <template <class...> class Trait, class... Args> using is_detected = typename tartan_detail::is_detected<Trait, void, Args...>::type; // end -- detection ideom template<typename T> // using subst_add_t = decltype(T::subst_add(declval<typename T::value_type &>(), declval<typename T::value_type>())); using subst_add_t = decltype(T::subst_add); template<typename T> using has_subst_add = is_detected<subst_add_t, T>; template<typename T> using add_t = decltype(T::add); template<typename T> using has_add = is_detected<add_t, T>; template<typename T> using subst_mult_t = decltype(T::subst_mult); template<typename T> using has_subst_mult = is_detected<subst_mult_t, T>; template<typename T> using mult_t = decltype(T::mult); template<typename T> using has_mult = is_detected<mult_t, T>; template<typename T> using subst_subt_t = decltype(T::subst_subt); template<typename T> using has_subst_subt = is_detected<subst_subt_t, T>; template<typename T> using subt_t = decltype(T::subt); template<typename T> using has_subt = is_detected<subt_t, T>; template <typename Opdef> struct MyAlg { using T = typename Opdef::value_type; using value_type = T; T v; MyAlg() {} MyAlg(const T& v_) : v(v_) {} MyAlg(T&& v_) : v(move(v_)) {} bool operator==(MyAlg o) const { return v == o.v; } bool operator!=(MyAlg o) const { return v != o.v; } operator T() const { return v; } MyAlg zero() const { return MyAlg(Opdef::zero(v)); } MyAlg one() const { return MyAlg(Opdef::one(v)); } MyAlg inverse() const { return MyAlg(Opdef::inverse(v)); } MyAlg operator/=(const MyAlg& o) { return *this *= o.inverse(); } MyAlg operator/(const MyAlg& o) const { return (*this) * o.inverse(); } MyAlg operator-() const { return zero() - *this; } MyAlg& operator +=(const MyAlg& o) { if constexpr (has_subst_add<Opdef>::value) { Opdef::subst_add(v, o.v); return *this; }else if constexpr (has_add<Opdef>::value) { v = Opdef::add(v, o.v); return *this; }else static_assert("either subst_add or add is needed."); } MyAlg operator +(const MyAlg& o) const { if constexpr (has_add<Opdef>::value) { return MyAlg(Opdef::add(v, o.v)); }else if constexpr (has_subst_add<Opdef>::value) { MyAlg ret(v); Opdef::subst_add(ret.v, o.v); return ret; }else static_assert("either subst_add or add is needed."); } MyAlg& operator *=(const MyAlg& o) { if constexpr (has_subst_mult<Opdef>::value) { Opdef::subst_mult(v, o.v); return *this; }else if constexpr (has_mult<Opdef>::value) { v = Opdef::mult(v, o.v); return *this; }else static_assert("either subst_mult or mult is needed."); } MyAlg operator *(const MyAlg& o) const { if constexpr (has_mult<Opdef>::value) { return MyAlg(Opdef::mult(v, o.v)); }else if constexpr (has_subst_mult<Opdef>::value) { MyAlg ret(v); Opdef::subst_mult(ret.v, o.v); return ret; }else static_assert("either subst_mult or mult is needed."); } MyAlg& operator -=(const MyAlg& o) { if constexpr (has_subst_subt<Opdef>::value) { Opdef::subst_subt(v, o.v); return *this; }else if constexpr (has_subt<Opdef>::value) { v = Opdef::subt(v, o.v); return *this; }else static_assert("either subst_subt or subt is needed."); } MyAlg operator -(const MyAlg& o) const { if constexpr (has_subt<Opdef>::value) { return MyAlg(Opdef::subt(v, o.v)); }else if constexpr (has_subst_subt<Opdef>::value) { MyAlg ret(v); Opdef::subst_subt(ret.v, o.v); return ret; }else static_assert("either subst_subt or subt is needed."); } friend istream& operator >>(istream& is, MyAlg& t) { is >> t.v; return is; } friend ostream& operator <<(ostream& os, const MyAlg& t) { os << t.v; return os; } }; // ---- end algOp.cc // ---- inserted function f:gcd from util.cc // auto [g, s, t] = eGCD(a, b) // g == gcd(|a|, |b|) and as + bt == g // It guarantees that max(|s|, |t|) <= max(|a| / g, |b| / g) (when g != 0) // Note that gcd(a, 0) == gcd(0, a) == a. template<typename INT=ll> tuple<INT, INT, INT> eGCD(INT a, INT b) { INT sa = a < 0 ? -1 : 1; INT ta = 0; INT za = a * sa; INT sb = 0; INT tb = b < 0 ? -1 : 1; INT zb = b * tb; while (zb != 0) { INT q = za / zb; INT r = za % zb; za = zb; zb = r; INT new_sb = sa - q * sb; sa = sb; sb = new_sb; INT new_tb = ta - q * tb; ta = tb; tb = new_tb; } return {za, sa, ta}; } pair<ll, ll> crt_sub(ll a1, ll x1, ll a2, ll x2) { // DLOGKL("crt_sub", a1, x1, a2, x2); a1 = a1 % x1; a2 = a2 % x2; auto [g, s, t] = eGCD(x1, -x2); ll gq = (a2 - a1) / g; ll gr = (a2 - a1) % g; if (gr != 0) return {-1, -1}; s *= gq; t *= gq; ll z = x1 / g * x2; // DLOGK(z); s = s % (x2 / g); ll r = (x1 * s + a1) % z; // DLOGK(r); if (r < 0) r += z; // DLOGK(r); return {r, z}; }; // Chinese Remainder Theorem // // r = crt(a1, x1, a2, x2) // ==> r = a1 (mod x1); r = a2 (mod x2); 0 <= r < lcm(x1, x2) // If no such r exists, returns -1 // Note: x1 and x2 should >= 1. a1 and a2 can be negative or zero. // // r = crt(as, xs) // ==> for all i. r = as[i] (mod xs[i]); 0 <= r < lcm(xs) // If no such r exists, returns -1 // Note: xs[i] should >= 1. as[i] can be negative or zero. // It should hold: len(xs) == len(as) > 0 ll crt(ll a1, ll x1, ll a2, ll x2) { return crt_sub(a1, x1, a2, x2).first; } ll crt(vector<ll> as, vector<ll> xs) { // DLOGKL("crt", as, xs); assert(xs.size() == as.size() && xs.size() > 0); ll r = as[0]; ll z = xs[0]; for (size_t i = 1; i < xs.size(); i++) { // DLOGK(i, r, z, as[i], xs[i]); tie(r, z) = crt_sub(r, z, as[i], xs[i]); // DLOGK(r, z); if (r == -1) return -1; } return r; } // ---- end f:gcd // ---- inserted library file mod.cc template<int mod=0, typename INT=ll> struct FpG { // G for General static INT dyn_mod; static INT getMod() { if (mod == 0) return dyn_mod; else return (INT)mod; } // Effective only when mod == 0. // _mod must be less than the half of the maximum value of INT. static void setMod(INT _mod) { dyn_mod = _mod; } static INT _conv(INT x) { if (x >= getMod()) return x % getMod(); if (x >= 0) return x; if (x >= -getMod()) return x + getMod(); INT y = x % getMod(); if (y == 0) return 0; return y + getMod(); } INT val; FpG(INT t = 0) : val(_conv(t)) {} FpG(const FpG& t) : val(t.val) {} FpG& operator =(const FpG& t) { val = t.val; return *this; } FpG& operator =(INT t) { val = _conv(t); return *this; } FpG& operator +=(const FpG& t) { val += t.val; if (val >= getMod()) val -= getMod(); return *this; } FpG& operator -=(const FpG& t) { val -= t.val; if (val < 0) val += getMod(); return *this; } FpG& operator *=(const FpG& t) { val = (val * t.val) % getMod(); return *this; } FpG inv() const { if (val == 0) { throw runtime_error("FpG::inv(): called for zero."); } auto [g, u, v] = eGCD(val, getMod()); if (g != 1) { throw runtime_error("FpG::inv(): not co-prime."); } return FpG(u); } FpG zero() const { return (FpG)0; } FpG one() const { return (FpG)1; } FpG inverse() const { return inv(); } FpG& operator /=(const FpG& t) { return (*this) *= t.inv(); } FpG operator +(const FpG& t) const { return FpG(val) += t; } FpG operator -(const FpG& t) const { return FpG(val) -= t; } FpG operator *(const FpG& t) const { return FpG(val) *= t; } FpG operator /(const FpG& t) const { return FpG(val) /= t; } FpG operator -() const { return FpG(-val); } bool operator ==(const FpG& t) const { return val == t.val; } bool operator !=(const FpG& t) const { return val != t.val; } operator INT() const { return val; } friend FpG operator +(INT x, const FpG& y) { return FpG(x) + y; } friend FpG operator -(INT x, const FpG& y) { return FpG(x) - y; } friend FpG operator *(INT x, const FpG& y) { return FpG(x) * y; } friend FpG operator /(INT x, const FpG& y) { return FpG(x) / y; } friend bool operator ==(INT x, const FpG& y) { return FpG(x) == y; } friend bool operator !=(INT x, const FpG& y) { return FpG(x) != y; } friend FpG operator +(const FpG& x, INT y) { return x + FpG(y); } friend FpG operator -(const FpG& x, INT y) { return x - FpG(y); } friend FpG operator *(const FpG& x, INT y) { return x * FpG(y); } friend FpG operator /(const FpG& x, INT y) { return x / FpG(y); } friend bool operator ==(const FpG& x, INT y) { return x == FpG(y); } friend bool operator !=(const FpG& x, INT y) { return x != FpG(y); } /* The following are needed to avoid warnings in cases such as FpG x; x = 5 + x; rather than x = FpG(5) + x; */ friend FpG operator +(int x, const FpG& y) { return FpG(x) + y; } friend FpG operator -(int x, const FpG& y) { return FpG(x) - y; } friend FpG operator *(int x, const FpG& y) { return FpG(x) * y; } friend FpG operator /(int x, const FpG& y) { return FpG(x) / y; } friend bool operator ==(int x, const FpG& y) { return FpG(x) == y; } friend bool operator !=(int x, const FpG& y) { return FpG(x) != y; } friend FpG operator +(const FpG& x, int y) { return x + FpG(y); } friend FpG operator -(const FpG& x, int y) { return x - FpG(y); } friend FpG operator *(const FpG& x, int y) { return x * FpG(y); } friend FpG operator /(const FpG& x, int y) { return x / FpG(y); } friend bool operator ==(const FpG& x, int y) { return x == FpG(y); } friend bool operator !=(const FpG& x, int y) { return x != FpG(y); } friend istream& operator>> (istream& is, FpG& t) { INT x; is >> x; t = x; return is; } friend ostream& operator<< (ostream& os, const FpG& t) { os << t.val; return os; } }; template<int mod, typename INT> INT FpG<mod, INT>::dyn_mod; template<typename T> class Comb { int nMax; vector<T> vFact; vector<T> vInvFact; public: Comb(int nm) : nMax(nm), vFact(nm+1), vInvFact(nm+1) { vFact[0] = 1; for (int i = 1; i <= nMax; i++) vFact[i] = i * vFact[i-1]; vInvFact.at(nMax) = (T)1 / vFact[nMax]; for (int i = nMax; i >= 1; i--) vInvFact[i-1] = i * vInvFact[i]; } T fact(int n) { return vFact[n]; } T binom(int n, int r) { if (r < 0 || r > n) return (T)0; return vFact[n] * vInvFact[r] * vInvFact[n-r]; } T binom_dup(int n, int r) { return binom(n + r - 1, r); } // The number of permutation extracting r from n. T perm(int n, int r) { return vFact[n] * vInvFact[n-r]; } }; constexpr int primeA = 1'000'000'007; constexpr int primeB = 998'244'353; // ' using FpA = FpG<primeA, ll>; using FpB = FpG<primeB, ll>; // ---- end mod.cc // ---- inserted library file random.cc struct Random { static random_device the_random_device; mt19937_64 rng; Random() : rng(the_random_device()) {} Random(unsigned seed) : rng(seed) {} ll range(ll i, ll j) { if (i >= j) { throw runtime_error("Random.range: invalid range"); } uniform_int_distribution<ll> dist(i, j - 1); return dist(rng); } }; random_device Random::the_random_device; // ---- end random.cc // ---- inserted library file power.cc template<typename T> T power(const T& a, ll b) { auto two_pow = a; auto ret = one<T>(a); while (b > 0) { if (b & 1LL) ret *= two_pow; two_pow *= two_pow; b >>= 1; } return ret; } // a >= 0, b >= 0; If overflow, returns -1. ll llpower(ll a, ll b) { if (b == 0) return 1; // 0^0 == 1 if (b == 1) return a; if (a == 0) return 0; if (a == 1) return 1; if (a == 2) { if (b >= 63) return -1; else return 1LL << b; } if (b == 2) { ll ret; if (__builtin_smulll_overflow(a, a, &ret)) return -1; return ret; } ll two_pow = a; ll ret = 1; assert(b > 0); while (true) { if (b & 1LL) { if (__builtin_smulll_overflow(ret, two_pow, &ret)) return -1; } b >>= 1; if (b == 0) break; if (__builtin_smulll_overflow(two_pow, two_pow, &two_pow)) return -1; } return ret; } // a >= 0; Returns x s.t. x*x <= a < (x+1)*(x+1) ll llsqrt(ll a) { ll x = llround(sqrt((double)a)); ll y; if (__builtin_smulll_overflow(x, x, &y) or a < y) return x - 1; else return x; } // a >= 0, m >= 2; Returns x s.t. x^m <= a < (x + 1)^m ll llroot(ll a, ll m) { ll x = llround(pow(a, 1.0 / m)); ll y = llpower(x, m); if (y == -1 or a < y) return x - 1; else return x; } // base >= 2, a >= 1; Returns x s.t. base^{x} <= a < base^{x + 1} ll lllog(ll base, ll a) { ll x = llround(log(a) / log(base)); ll y = llpower(base, x); if (y == -1 or a < y) return x - 1; else return x; } // ---- end power.cc // ---- inserted library file sieve.cc // sieve(upto) returns the list of prime numbers up to upto. // Size: upto(1e8).size() ... 5.7e6, upto(1e9).size() ... 5.1e7 // Performance: upto(1e8) ... 0.7sec, upto(1e9) ... 9.2sec vector<int> sieve(int upto) { vector<int> res; vector<bool> tbl(upto+1); ll lim = (int)(sqrt((double)upto)) + 1; for (int x = 2; x <= upto; x++) { if (tbl[x]) continue; res.push_back(x); if (x <= lim) { for (int y = x * x; y <= upto; y += x) tbl[y] = true; } } return res; } vector<int> divisorSieve(int upto) { vector<int> tbl(upto+1); iota(tbl.begin(), tbl.end(), 0); ll lim = (int)(sqrt((double)upto)) + 1; for (int x = 2; x <= lim; x++) { if (tbl[x] < x) continue; for (int y = x * x; y <= upto; y += x) if (tbl[y] == y) tbl[y] = x; } return tbl; } /* Prime Factorization Two versions: - prfac(n) - prfac(n, primes) primes should contain prime numbers at least up to sqrt(n) */ struct myiter_primes { const vector<int>& primes; int i; myiter_primes(const auto& primes_) : primes(primes_), i(0) {} int next() { if (i == ssize(primes)) return -1; else return primes[i++]; } }; struct myiter_int { int x; myiter_int() : x(0) {} int next() { x++; if (x == 1) { return 2; } if (x == 2) { return 3; } if (x % 2 == 1) { return 3 * x - 4; } return 3 * x - 5; } }; vector<pair<ll, int>> _prfac_sub(ll n, auto& mit) { vector<pair<ll, int>> res; ll x = n; while (x > 1) { ll p = mit.next(); if (p < 0) { throw runtime_error("_prfac_sub: prime range too small"); } if (p * p > x) break; int r = 0; while (x % p == 0) { x /= p; r++; } if (r > 0) res.push_back(make_pair(p, r)); } if (x > 1) res.push_back(make_pair(x, 1)); return res; } vector<pair<ll, int>> prfac(ll n) { myiter_int mit; return _prfac_sub(n, mit); } vector<pair<ll, int>> prfac(ll n, const vector<int>& primes) { myiter_primes mit(primes); return _prfac_sub(n, mit); } vector<pair<int, int>> prfacDivSieve(int n, const vector<int>& divSieve) { vector<pair<int, int>> ret; int p = -1; int r = 0; while (n > 1) { int q = divSieve[n]; if (p == q) { r++; }else { if (p > 0) ret.emplace_back(p, r); p = q; r = 1; } n /= p; } if (p > 0) ret.emplace_back(p, r); return ret; } /* List of divisors - getDivisors(n) - getDivisors(n, primes) primes should contain prime numbers at least up to sqrt(n) Note: the results are NOT sorted */ // _gdsub ... aux function used in getDivisors() vector<ll> _gdsub(int i, const auto& fs) { if (i == (int)fs.size()) { return vector<ll>({1}); } auto part = _gdsub(i+1, fs); auto [p, r] = fs[i]; ll pp = 1; // pp = p^m, for m \in [1, r] int partOrigLen = part.size(); for (int m = 1; m <= r; m++) { pp *= p; for (int j = 0; j < partOrigLen; j++) part.push_back(pp * part[j]); } return part; } vector<ll> getDivisors(ll n) { return _gdsub(0, prfac(n)); } vector<ll> getDivisors(ll n, const vector<int>& primes) { return _gdsub(0, prfac(n, primes)); } vector<ll> getDivisorsDivSieve(ll n, const vector<int>& divSieve) { return _gdsub(0, prfacDivSieve(n, divSieve)); } // Miller-Rabin prime judgement // is_prime_MR(n) returns true iff n is prime for u64 n. // The original code is on https://zenn.dev/mizar/articles/791698ea860581 #include <cstdbool> #include <cstdint> uint64_t modmul(uint64_t a, uint64_t b, uint64_t n) { return (uint64_t)(((__uint128_t)a) * ((__uint128_t)b) % ((__uint128_t)n)); } uint64_t modpow(uint64_t a, uint64_t b, uint64_t n) { uint64_t t = ((b & 1) == 0) ? 1 : a; for (b >>= 1; b != 0; b >>= 1) { a = modmul(a, a, n); if ((b & 1) == 1) { t = modmul(t, a, n); } } return t; } const uint64_t bases[] = {2,325,9375,28178,450775,9780504,1795265022}; bool is_prime_MR(uint64_t n) { if (n == 2) { return true; } if (n < 2 || (n & 1) == 0) { return false; } uint64_t n1 = n - 1, d = n - 1; uint32_t s = 0; for (; (d & 1) == 0; d >>= 1) { s += 1; } for (const auto& base : bases) { uint64_t a = base; if (a >= n) { a %= n; if (a == 0) { continue; } } uint64_t t = modpow(a, d, n); if (t == 1) { continue; } for (uint32_t j = 1; t != n1; ++j) { if (j >= s) { return false; } t = modmul(t, t, n); } } return true; } ll findPrimeFactor(ll n) { if (n % 2 == 0) return 2; ll m = llround(ceil(pow((double)n, 0.125))); auto loop_c = [&]() -> ll { auto sub_c = [&](int c) -> ll { ll y = 0; auto sub_r = [&](int r) -> ll { auto next_rand = [&](__int128 a) -> ll { return (a * a + c) % n; }; ll x = y; int th1 = 3 * r / 4; for (int k = 0; k < th1; k++) y = next_rand(y); for (int j = 0; th1 + j * m < r; j++) { auto sub_range_all = [&](ll st, ll len) -> ll { ll en = st + len > r ? r : st + len; ll q = 1; for (int k = st; k < en; k++) { y = next_rand(y); q = (__int128)q * abs(x - y) % n; } return gcd(q, n); }; auto sub_range_each = [&](ll st, ll len) -> ll { ll en = st + len > r ? r : st + len; for (int k = st; k < en; k++) { y = next_rand(y); if (ll g = gcd(abs(x - y), n); g != 1) return g; } assert(0); }; ll y_save = y; auto g = sub_range_all(th1 + j * m, m); if (g == n) { y = y_save; return sub_range_each(th1 + j * m, m); }else if (g != 1) return g; } return 1; }; for (int r = 1; true; r *= 2) { if (ll res = sub_r(r); res != 1) return res; } }; for (int c = 1; true; c++) { if (ll res = sub_c(c); res != n) return res; } }; ll v = loop_c(); if (is_prime_MR(v )) return v; else if (is_prime_MR(n / v)) return n / v; else return findPrimeFactor(v); } vector<pair<ll, int>> prfacPollardsRho(ll n) { vector<pair<ll, int>> ret; while (n > 1 and not is_prime_MR(n)) { ll p = findPrimeFactor(n); int r = 0; while (n % p == 0) { n /= p; r++; } ret.emplace_back(p, r); } if (n > 1) ret.emplace_back(n, 1); sort(ret.begin(), ret.end()); return ret; } // ---- end sieve.cc // @@ !! LIM -- end mark -- int main(/* int argc, char *argv[] */) { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout << setprecision(20); ll lim = (ll)1e7 + 1000; auto primes = sieve(lim); vector<ll> twp; REP(i, 0, ssize(primes) - 1) { if (primes[i] + 2 == primes[i + 1]) twp.push_back((ll)primes[i] * (ll)primes[i + 1]); } auto solve = [&](ll N) -> ll { ll i = lower_bound(ALL(twp), N + 1) - twp.begin(); i--; if (i < 0) return -1; return twp[i]; }; ll T; cin >> T; REP(i, 0, T) { ll N; cin >> N; cout << solve(N) << "\n"; } return 0; }