結果
問題 |
No.3127 Multiple of Twin Prime
|
ユーザー |
|
提出日時 | 2025-04-25 21:45:04 |
言語 | D (dmd 2.109.1) |
結果 |
AC
|
実行時間 | 574 ms / 2,500 ms |
コード長 | 7,127 bytes |
コンパイル時間 | 4,116 ms |
コンパイル使用メモリ | 213,628 KB |
実行使用メモリ | 129,372 KB |
最終ジャッジ日時 | 2025-04-25 21:45:31 |
合計ジャッジ時間 | 13,123 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 12 |
ソースコード
import std; void main () { int T = readln.chomp.to!int; // 先に列挙 -> 二分探索で解けるには解けるが、計算量がかなり怪しい alias ls = LinearSieve; ls.build(10 ^^ 7); auto candi = new long[](0); foreach (i; 2 .. 10 ^^ 7) { if (ls.is_prime(i) && ls.is_prime(i + 2)) { candi ~= 1L * i * (i + 2); } } auto ans = new long[](T); foreach (caseid; 0 .. T) { long N = readln.chomp.to!long; auto ret = bsearch!((int id) => candi[id] <= N)(0, candi.length.to!int - 1); if (ret.empty) { ans[caseid] = -1; } else { ans[caseid] = candi[ret.value]; } } writefln("%(%s\n%)", ans); } void read (T...) (string S, ref T args) { import std.conv : to; import std.array : split; auto buf = S.split; foreach (i, ref arg; args) { arg = buf[i].to!(typeof(arg)); } } import std.typecons : Tuple, tuple; class LinearSieve { /// methods /// - void build (ulong N_) /// - Tuple!(long, long)[] prime_factors (ulong N_) /// - bool is_prime (ulong N_) /// - long[] divisors (ulong N_) private: static int N = 0; static int[] lpf; static int[] primes; static int[] lpf_ord; static int[] lpf_pow; import std.conv : to; import std.format : format; public: @disable this () {} static void build (ulong N_) in { assert(2 <= N_ && N_ <= int.max, format("Argument N_ = %s does not meet condition.", N_)); } do { // Linear sieve. if (N+1 <= lpf.length) return; N = N_.to!int; primes.length = 0; lpf.length = N+1; lpf[0] = lpf[1] = 1; for (int i = 2; i <= N; i++) { if (lpf[i] == 0) { lpf[i] = i; primes ~= i; } foreach (p; primes) { if (lpf[i] < p) break; if (N < 1L * i * p) break; lpf[i * p] = p; } } // Precomputation of prime factorization. lpf_ord.length = lpf_pow.length = N+1; lpf_pow[] = 1; for (int i = 2; i <= N; i++) { int prev = i / lpf[i]; if (lpf[i] == lpf[prev]) { lpf_ord[i] = lpf_ord[prev] + 1; lpf_pow[i] = lpf_pow[prev] * lpf[i]; } else { lpf_ord[i] = 1; lpf_pow[i] = lpf[i]; } } } static Tuple!(long, long)[] prime_factors (ulong N_) in { assert(2 <= N_ && N_ <= N, format("Argument N_ = %s is not out of range. The valid range is [2, %s].", N_, N)); } do { int n = N_.to!int; Tuple!(long, long)[] res; while (1 < n) { res ~= tuple(1L*lpf[n], 1L*lpf_ord[n]); n /= lpf_pow[n]; } return res; } static bool is_prime (ulong N_) in { assert(2 <= N_ && N_ <= N, format("Argument N_ = %s is not out of range. The valid range is [2, %s].", N_, N)); } do { int N = N_.to!int; return lpf[N] == N; } static long[] divisors (ulong N_) in { assert(N_ <= N, format("Argument N_ = %s is not out of range. The valid range is [2, %s].", N_, N)); } do { if (N_ == 1) return [1L]; import std.container : SList; import std.algorithm : sort; auto fac = prime_factors(N_); static SList!(Tuple!(int, long)) Q; Q.insertFront(tuple(0, 1L)); // (処理済み階層, 値) long[] res; while (!Q.empty) { auto h = Q.front; Q.removeFront; if (h[0] == fac.length) { res ~= h[1]; continue; } auto p = fac[h[0]]; long prod = 1; foreach (i; 0..p[1] + 1) { Q.insertFront(tuple(h[0] + 1, h[1] * prod)); prod *= p[0]; } } res.sort; return res; } } import std.traits : isIntegral; import std.int128 : Int128; class NoTrueRangeException: Exception { import std.exception: basicExceptionCtors; mixin basicExceptionCtors; } class BsearchException: Exception { import std.exception: basicExceptionCtors; mixin basicExceptionCtors; } struct BsearchResult (T) { import std.format: format; private bool has_value = true; private T l, r; private T _value; this (T _l, T _r) { this.l = _l; this.r = _r; this.has_value = false; } this (T _l, T _r, T _value) { this.l = _l; this.r = _r; this._value = _value; } bool empty () { return !this.has_value; } T value () { if (this.empty()) { throw new NoTrueRangeException( format("No true condition found in the range [%s, %s].", l, r)); } return _value; }; } BsearchResult!T bsearch (alias func, T) (T l, T r) if ((isIntegral!(T) || is(T == Int128)) && !is(T == byte) && !is(T == ubyte) && !is(T == short) && !is(T == ushort)) { import std.traits : isCallable, ReturnType, Parameters; import std.meta : AliasSeq; static assert(isCallable!(func)); static assert(is(ReturnType!(func) == bool)); static assert(is(Parameters!(func) == AliasSeq!(T))); import std.algorithm.comparison : min, max; T L = l, R = r; if (l == r) { if (func(l)) return BsearchResult!(T)(L, R, l); return BsearchResult!(T)(L, R); } while (min(l, r) + 1 < max(l, r)) { T m = midpoint(l, r); if (func(m)) { l = m; } else { r = m; } } bool lb = func(l); if (!lb) return BsearchResult!(T)(L, R); bool rb = func(r); if (rb) return BsearchResult!(T)(L, R, r); if (!rb) return BsearchResult!(T)(L, R, l); throw new BsearchException(format("This code path should never be reached. l: %s, r: %s.", L, R)); } T midpoint (T) (T a, T b) if (isIntegral!(T) || is(T == Int128)) { static if (is(T == short) || is(T == ushort) || is(T == byte) || is(T == ubyte)) { import std.conv : to; int x = a, y = b; return midpoint(x, y).to!(T); } else { import std.math.algebraic : abs; import std.algorithm.comparison : min, max; int as = (0 <= a) ? 1 : -1, bs = (0 <= b) ? 1 : -1; if (as == bs) { if (as == 1) { return min(a, b) + (max(a, b) - min(a, b)) / 2; } return max(a, b) + (min(a, b) - max(a, b)) / 2; } return (a + b) / 2; } }