Skip to content

Commit e145e17

Browse files
committed
Sieve in O(N)
1 parent 6b89346 commit e145e17

10 files changed

+121
-20
lines changed

number/README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,14 @@
22

33
## Contents
44

5-
- `eratosthenes.hpp` Sieve of eratosthenes
5+
- `count_primes.hpp` Prime-counting function, O(N^(2/3))
66
- `cyclotomic_polynomials.hpp` Cyclotomic polynomial (円分多項式, $x^k - 1$の因数分解など)
7+
- `discrete_logarithm.hpp` Discrete logarithm by the baby-step giant-step algorithm
8+
- `enumerate_partitions.hpp` 自然数の分割の列挙
9+
- `euler_toptient_phi.hpp` Generate table of Euler's totient function
10+
- `factorize.hpp` 大きい整数の素因数分解・素数判定
11+
- `modint_runtime.hpp` 実行時 modint (`modint.hpp` と共通のインターフェース)
12+
- `sieve.hpp` 線形篩・素因数分解・メビウス関数
713

814
## Cyclotomic Polynomials
915

number/count_primes.hpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
// CUT begin
77
struct CountPrimes {
8-
// Count Primes less than x (\pi(x)) for each x = N / i (i = 1, ..., N) in O(N^(2/3)) time
8+
// Count Primes less than or equal to x (\pi(x)) for each x = N / i (i = 1, ..., N) in O(N^(2/3)) time
99
// Learned this algorihtm from <https://old.yosupo.jp/submission/14650>
1010
// Reference: <https://min-25.hatenablog.com/entry/2018/11/11/172216>
1111
using Int = long long;
@@ -36,7 +36,8 @@ struct CountPrimes {
3636
for (size_t j = p * 2; j < is_prime.size(); j += p) is_prime[j] = 0;
3737
}
3838
}
39-
for (Int now = n; now; now = n / (n / now + 1)) vs.push_back(now); // [N, N / 2, ..., 1], Relevant integers (decreasing) length ~= 2sqrt(N)
39+
for (Int now = n; now; now = n / (n / now + 1))
40+
vs.push_back(now); // [N, N / 2, ..., 1], Relevant integers (decreasing) length ~= 2sqrt(N)
4041
s = vs.size();
4142

4243
// pi[i] = (# of integers x s.t. x <= vs[i], (x is prime or all factors of x >= p))
@@ -74,8 +75,9 @@ struct CountPrimes {
7475
};
7576
for (; primes[ip] <= n3; ip++, pre++) {
7677
const auto &p = primes[ip];
77-
for (int i = 0; i < n3 and p * p <= vs[i]; i++) trans2(i, p); // upto n3, total trans2 times: O(N^(2/3) / logN)
78-
_fenwick_rec_update(ip, primes[ip], true); // total update times: O(N^(2/3) / logN)
78+
for (int i = 0; i < n3 and p * p <= vs[i]; i++)
79+
trans2(i, p); // upto n3, total trans2 times: O(N^(2/3) / logN)
80+
_fenwick_rec_update(ip, primes[ip], true); // total update times: O(N^(2/3) / logN)
7981
}
8082
for (int i = s - n3 - 1; i >= 0; i--) {
8183
int j = i + ((i + 1) & (-i - 1));

number/cyclotomic_polynomials.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#pragma once
2-
#include "number/eratosthenes.hpp"
2+
#include "sieve.hpp"
33
#include <vector>
44

55
// CUT begin
66
// cyclotomic polynominals : 円分多項式
77
// ret[i][j] = [x^j]\Phi_i(x) for i <= Nmax, which are known to be integers
88
std::vector<std::vector<int>> cyclotomic_polynomials(int Nmax) {
9-
std::vector<int> moebius = SieveOfEratosthenes(Nmax).GenerateMoebiusFunctionTable();
9+
std::vector<int> moebius = Sieve(Nmax).GenerateMoebiusFunctionTable();
1010
std::vector<std::vector<int>> ret(Nmax + 1);
1111
auto multiply = [](const std::vector<int> &a, const std::vector<int> &b) { // a * b
1212
std::vector<int> ret(int(a.size() + b.size()) - 1);

number/enumerate_partitions.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55
// CUT begin
66
// Enumerate Partitions of number <= N (自然数の分割の列挙)
7-
// - can be used for N less than ~50
7+
// N = 50: 221 MB, 274 ms (length = 1295970) (g++, C++17, AtCoder)
88
// - Example:
99
// - 1 => [[1,],]
1010
// - 2 => [[1,],[1,1,],[2,],]
1111
// - 3 => [[1,],[1,1,],[1,1,1,],[2,],[2,1,],[3,],]
12+
// 分割数の一覧:<https://oeis.org/A000041/list>
1213
struct {
1314
std::vector<std::vector<int>> ret;
1415
std::vector<int> now;

number/eratosthenes.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// (*this)[i] = (divisor of i, greater than 1)
1010
// Example: [0, 1, 2, 3, 2, 5, 3, 7, 2, 3, 2, 11, ...]
1111
// Complexity: Space O(MAXN), Time (construction) O(MAXNloglogMAXN)
12-
struct SieveOfEratosthenes : std::vector<int> {
12+
struct [[deprecated("Use sieve.hpp (linear time complexity)")]] SieveOfEratosthenes : std::vector<int> {
1313
std::vector<int> primes;
1414
SieveOfEratosthenes(int MAXN) : std::vector<int>(MAXN + 1) {
1515
std::iota(begin(), end(), 0);

number/sieve.hpp

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#pragma once
2+
#include <cassert>
3+
#include <map>
4+
#include <vector>
5+
6+
// CUT begin
7+
// Linear sieve algorithm for fast prime factorization
8+
// Complexity: O(N) time, O(N) space:
9+
// - MAXN = 10^7: ~44 MB, 80~100 ms (Codeforces / AtCoder GCC, C++17)
10+
// - MAXN = 10^8: ~435 MB, 810~980 ms (Codeforces / AtCoder GCC, C++17)
11+
// Reference:
12+
// [1] D. Gries, J. Misra, "A Linear Sieve Algorithm for Finding Prime Numbers,"
13+
// Communications of the ACM, 21(12), 999-1003, 1978.
14+
// - <https://cp-algorithms.com/algebra/prime-sieve-linear.html>
15+
// - <https://37zigen.com/linear-sieve/>
16+
struct Sieve {
17+
std::vector<int> min_factor;
18+
std::vector<int> primes;
19+
Sieve(int MAXN) : min_factor(MAXN + 1) {
20+
for (int d = 2; d <= MAXN; d++) {
21+
if (!min_factor[d]) {
22+
min_factor[d] = d;
23+
primes.emplace_back(d);
24+
}
25+
for (const auto &p : primes) {
26+
if (p > min_factor[d] or d * p > MAXN) break;
27+
min_factor[d * p] = p;
28+
}
29+
}
30+
}
31+
// Prime factorization for 1 <= x <= MAXN^2
32+
// Complexity: O(log x) (x <= MAXN)
33+
// O(MAXN / log MAXN) (MAXN < x <= MAXN^2)
34+
template <typename T> std::map<T, int> factorize(T x) {
35+
std::map<T, int> ret;
36+
assert(x > 0 and x <= ((long long)min_factor.size() - 1) * ((long long)min_factor.size() - 1));
37+
for (const auto &p : primes) {
38+
if (x < T(min_factor.size())) break;
39+
while (!(x % p)) x /= p, ret[p]++;
40+
}
41+
if (x >= T(min_factor.size())) ret[x]++, x = 1;
42+
while (x > 1) ret[min_factor[x]]++, x /= min_factor[x];
43+
return ret;
44+
}
45+
// Enumerate divisors of 1 <= x <= MAXN^2
46+
// Be careful of highly composite numbers <https://oeis.org/A002182/list> <https://gist.github.com/dario2994/fb4713f252ca86c1254d#file-list-txt>:
47+
// (n, (# of div. of n)): 45360->100, 735134400(<1e9)->1344, 963761198400(<1e12)->6720
48+
template <typename T> std::vector<T> divisors(T x) {
49+
std::vector<T> ret{1};
50+
for (const auto p : factorize(x)) {
51+
int n = ret.size();
52+
for (int i = 0; i < n; i++) {
53+
for (T a = 1, d = 1; d <= p.second; d++) {
54+
a *= p.first;
55+
ret.push_back(ret[i] * a);
56+
}
57+
}
58+
}
59+
return ret; // NOT sorted
60+
}
61+
// Moebius function Table, (-1)^{# of different prime factors} for square-free x
62+
// return: [0=>0, 1=>1, 2=>-1, 3=>-1, 4=>0, 5=>-1, 6=>1, 7=>-1, 8=>0, ...] <https://oeis.org/A008683>
63+
std::vector<int> GenerateMoebiusFunctionTable() {
64+
std::vector<int> ret(min_factor.size());
65+
for (unsigned i = 1; i < min_factor.size(); i++) {
66+
if (i == 1)
67+
ret[i] = 1;
68+
else if ((i / min_factor[i]) % min_factor[i] == 0)
69+
ret[i] = 0;
70+
else
71+
ret[i] = -ret[i / min_factor[i]];
72+
}
73+
return ret;
74+
}
75+
};
76+
// Sieve sieve(1 << 15); // (can factorize n <= 10^9)

number/test/enumerate_primes.test.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#define PROBLEM "https://judge.yosupo.jp/problem/enumerate_primes"
2+
#include "../sieve.hpp"
3+
#include <iostream>
4+
#include <vector>
5+
using namespace std;
6+
7+
int main() {
8+
int N, A, B;
9+
cin >> N >> A >> B;
10+
Sieve sieve(N);
11+
vector<int> ret;
12+
for (unsigned i = 0; A * i + B < sieve.primes.size(); i++) ret.push_back(sieve.primes[A * i + B]);
13+
cout << sieve.primes.size() << ' ' << ret.size() << '\n';
14+
for (auto p : ret) cout << p << ' ';
15+
cout << '\n';
16+
}

number/test/gen_primes.test.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
#include "number/eratosthenes.hpp"
2-
#include <algorithm>
1+
#include "../sieve.hpp"
32
#include <iostream>
43
#include <vector>
54
#define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_1_C"
65
using namespace std;
76

87
int main() {
9-
SieveOfEratosthenes sieve(10000);
8+
Sieve sieve(10000);
109
int N;
1110
cin >> N;
1211
int ret = 0;
13-
for (int i = 0; i < N; i++) {
12+
while (N--) {
1413
int x;
1514
cin >> x;
1615
bool flg = true;
@@ -21,5 +20,5 @@ int main() {
2120
}
2221
ret += flg;
2322
}
24-
cout << ret << endl;
23+
cout << ret << '\n';
2524
}
+6-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
#include "number/eratosthenes.hpp"
1+
#include "../sieve.hpp"
22
#include <iostream>
33
#define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=NTL_1_A"
44
using namespace std;
55

66
int main() {
7-
SieveOfEratosthenes sieve(40000);
7+
Sieve sieve(1 << 15);
88
int N;
99
cin >> N;
10-
map<long long int, int> factors = sieve.Factorize(N);
11-
cout << N << ":";
10+
map<long long int, int> factors = sieve.factorize<long long>(N);
11+
cout << N << ':';
1212
for (auto p : factors) {
13-
while (p.second--) cout << " " << p.first;
13+
while (p.second--) cout << ' ' << p.first;
1414
}
15-
cout << endl;
15+
cout << '\n';
1616
}

utilities/segtree_relevant_points.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#pragma once
12
#include <algorithm>
23
#include <vector>
34

0 commit comments

Comments
 (0)