結果
問題 | No.1661 Sum is Prime (Hard Version) |
ユーザー | 👑 Nachia |
提出日時 | 2021-08-27 22:05:29 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 223 ms / 3,000 ms |
コード長 | 4,489 bytes |
コンパイル時間 | 1,569 ms |
コンパイル使用メモリ | 101,512 KB |
実行使用メモリ | 13,252 KB |
最終ジャッジ日時 | 2024-11-21 02:29:57 |
合計ジャッジ時間 | 3,673 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,820 KB |
testcase_01 | AC | 2 ms
6,816 KB |
testcase_02 | AC | 139 ms
12,328 KB |
testcase_03 | AC | 2 ms
6,820 KB |
testcase_04 | AC | 1 ms
6,820 KB |
testcase_05 | AC | 1 ms
6,816 KB |
testcase_06 | AC | 1 ms
6,816 KB |
testcase_07 | AC | 1 ms
6,820 KB |
testcase_08 | AC | 2 ms
6,820 KB |
testcase_09 | AC | 2 ms
6,816 KB |
testcase_10 | AC | 2 ms
6,820 KB |
testcase_11 | AC | 2 ms
6,816 KB |
testcase_12 | AC | 125 ms
9,036 KB |
testcase_13 | AC | 121 ms
9,104 KB |
testcase_14 | AC | 138 ms
9,108 KB |
testcase_15 | AC | 180 ms
11,592 KB |
testcase_16 | AC | 147 ms
12,136 KB |
testcase_17 | AC | 132 ms
9,616 KB |
testcase_18 | AC | 57 ms
7,736 KB |
testcase_19 | AC | 102 ms
8,368 KB |
testcase_20 | AC | 63 ms
7,752 KB |
testcase_21 | AC | 113 ms
12,356 KB |
testcase_22 | AC | 223 ms
13,252 KB |
testcase_23 | AC | 217 ms
12,764 KB |
ソースコード
#include <iostream> #include <vector> #include <algorithm> #include <cmath> using namespace std; using i32 = int32_t; using u32 = uint32_t; using i64 = int64_t; using u64 = uint64_t; #define rep(i,n) for(int i=0; i<(n); i++) // Prime Sieve {2, 3, 5, 7, 11, 13, 17, ...} vector<int> prime_enumerate(int N) { vector<bool> sieve(N / 3 + 1, 1); for (int p = 5, d = 4, i = 1, sqn = sqrt(N); p <= sqn; p += d = 6 - d, i++) { if (!sieve[i]) continue; for (int q = p * p / 3, r = d * p / 3 + (d * p % 3 == 2), s = 2 * p, qe = sieve.size(); q < qe; q += r = s - r) sieve[q] = 0; } vector<int> ret{2, 3}; for (int p = 5, d = 4, i = 1; p <= N; p += d = 6 - d, i++) if (sieve[i]) ret.push_back(p); while (!ret.empty() && ret.back() > N) ret.pop_back(); return ret; } inline int64_t my_div(int64_t n, int64_t p) { return double(n) / p; }; int64_t prime_counting(long long N) { if(N <= 0) return 0; using i64 = long long; i64 N6, N3, N2, N23, nsz; vector<i64> ns, h; vector<int> bit; // calculate N^{1/2}, N^{1/3}, N{1/6}, N{2/3} N2 = sqrt(N); N3 = pow(N, 1.0 / 3.0); while (N3 * N3 * N3 > N) N3--; while ((N3 + 1) * (N3 + 1) * (N3 + 1) <= N) N3++; N6 = sqrt(N3); N23 = N / N3; // precalc prime sieve below N ^ {1/2} auto prime = prime_enumerate(N2 + 1000); // index of prime int pidx = 0; // restore pi(p - 1) i64 pi = 0; // initialize ns ns.reserve(N2 * 2 + 2); ns.push_back(0); for (int i = 1; i <= N2; i++) ns.push_back(my_div(N, i)); for (int i = ns.back() - 1; i > 0; i--) ns.push_back(i); nsz = ns.size(); // initialize h copy(begin(ns), end(ns), back_inserter(h)); for (auto &i : h) --i; // p <= N ^ {1/6} while (prime[pidx] <= N6) { int p = prime[pidx]; i64 p2 = i64(p) * p; for (i64 i = 1, n = ns[i]; i < nsz && n >= p2; n = ns[++i]) h[i] -= h[i * p <= N2 ? i * p : nsz - my_div(n, p)] - pi; ++pidx; ++pi; } // fenwick tree, which restore [ h(p, 1), h(p, N ^ {2/3}) ) // bit[i] corresponds to h[i + N3] (1 <= i) bit.resize(nsz - N3); auto dfs = [&](auto rec, i64 cur, int pid, int flag) -> void { if (flag) { // if cur > N^{1/2} : // cur <= floor(N / id) // -> cur * id + n = N, n < id < cur // -> id <= floor(N / cur) int id = cur <= N2 ? nsz - cur : my_div(N, cur); // decrease h[N3] ~ h[id] if (id > N3) for (id -= N3; id; id -= id & -id) --bit[id]; } for (int dst = pid; cur * prime[dst] < N23; dst++) rec(rec, cur * prime[dst], dst, true); }; // N ^ {1/6} < p <= N ^ {1/3} while (prime[pidx] <= N3) { int p = prime[pidx]; i64 p2 = i64(p) * p; // update N ^ {2/3} <= n <= N for (i64 i = 1; i <= N3; i++) { // ns[i] >= p2 > N^{1/3} if (p2 > ns[i]) break; // id of floor(N/ip) int id = i * p <= N2 ? i * p : nsz - my_div(ns[i], p); // current value of h[id] i64 sm = h[id]; // if floor(N/ip) < N^{2/3}, add sum of fenwick tree if (id > N3) for (id -= N3; id < (int)bit.size(); id += id & -id) sm += bit[id]; h[i] -= sm - pi; } // update N ^ {1/3} <= n < N ^ {2/3}, using dfs dfs(dfs, p, pidx, false); ++pidx; ++pi; } // reflect fenwick tree for (int i = (int)bit.size() - 1; i; i--) { int j = i + (i & -i); if (j < (int)bit.size()) bit[i] += bit[j]; } for (int i = 1; i < (int)bit.size(); i++) h[i + N3] += bit[i]; // N ^ {1/3} < p <= N ^ {1/2} while (prime[pidx] <= N2) { int p = prime[pidx]; i64 p2 = i64(p) * p; for (i64 i = 1, n = ns[i]; i < nsz && n >= p2; n = ns[++i]) h[i] -= h[i * p <= N2 ? i * p : nsz - my_div(n, p)] - pi; ++pidx; ++pi; } return h[1]; } int solve(int L, int R){ int Z = R * 2; vector<int> sieve(Z+1,1); sieve[0] = sieve[1] = 0; for(int i=2; i*i<=Z; i++) if(sieve[i]){ for(int j=i*i; j<=Z; j+=i) sieve[j] = 0; } i64 ans = 0; for(int i=L; i<=R; i++) ans += sieve[i]; for(int i=L; i<R; i++) ans += sieve[i+i+1]; return ans; } int main(){ i64 L,R; cin >> L >> R; i64 ans = 0; if(R >= 1000000){ ans += prime_counting(R) - prime_counting(L-1); ans += prime_counting(R+R-1) - prime_counting(L+L-1); if(L == 1) ans--; } else{ ans = solve(L,R); } cout << ans << endl; return 0; } struct ios_do_not_sync{ ios_do_not_sync(){ ios::sync_with_stdio(false); cin.tie(nullptr); } } ios_do_not_sync_instance;