์ •์ˆ˜๋ก  ์ผ๋ฐ˜
ย - Last update: 2023-10-25

์ •์ˆ˜๋ก  ๊ธฐ๋ณธ ์ •๋ฆฌ

Basic Functions

GCD (์œ ํด๋ฆฌ๋“œ ํ˜ธ์ œ๋ฒ•)

  • GCD(a,b)=GCD(b,r)GCD(a, b) = GCD(b, r) (๋‹จ, rr์€ aa๋ฅผ bb๋กœ ๋‚˜๋ˆ„์—ˆ์„ ๋•Œ์˜ ๋‚˜๋จธ์ง€)์˜ ๊ตฌํ˜„์ด๋‹ค.
int gcd(int a, int b) {
return (b == 0) ? a : gcd(b, a % b); // a % b = r
}
int gcd(int a, int b) {
while (b != 0) {
int r = a % b;
a = b;
b = r;
}
return a;
}

LCM

int lcm(int a, int b) {
return a * b / gcd(a, b);
}

Simple isPrime

  • ๋ฃจํŠธ ์‹œ๊ฐ„๋ณต์žก๋„์ด๊ธฐ ๋•Œ๋ฌธ์— N<1,000,000N \lt 1,000,000 ์ •๋„์ผ ๋•Œ, ์ƒ๋‹นํžˆ ์œ ํšจํ•˜๋‹ค.
bool isPrime(int num) {
for(int i = 2; i * i <= num; ++i) {
if (num % i == 0) return false;
}
return true;
}

๋ฐ€๋Ÿฌ๋ผ๋นˆ isPrime

  • ํ™•๋ฅ ์  ์†Œ์ˆ˜ ํŒ์ •์ด์ง€๋งŒ, ํŠน์ • ์ˆ˜๋“ค์— ๋Œ€ํ•ด์„œ ๋ชจ๋‘ ์ฒดํฌํ•จ์œผ๋กœ์จ ํ™•์ •์ ์œผ๋กœ ์†Œ์ˆ˜ ์ฒดํฌ ๊ฐ€๋Šฅ
  • casterian๋‹˜ ์ฝ”๋“œ ์ฐธ๊ณ : https://casterian.net/archives/396
๐Ÿ‘‰ ํŽผ์น˜๊ธฐ
typedef unsigned long long ull;
ull checker[] = {2ULL, 325ULL, 9375ULL, 28178ULL, 450775ULL, 9780504ULL, 1795265022ULL};
// int checker[] = {2, 7, 61}; // int ๋ฒ”์œ„์ผ ๋•Œ
ull addmod(ull x, ull y, ull m) {
if (x >= m - y) {
return x - (m - y);
} else {
return x + y;
}
}
ull mulmod(ull x, ull y, ull m) {
ull r = 0ULL;
while (y > 0) {
if (y % 2 == 1)
r = addmod(r, x, m);
x = addmod(x, x, m);
y /= 2;
}
return r;
}
ull powmod(ull x, ull y, ull m) {
ull r = 1ULL;
while (y > 0) {
if (y % 2 == 1) {
r = mulmod(r, x, m);
}
x = mulmod(x, x, m);
y /= 2;
}
return r;
}
// Miller-Rabin checker
// true๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค๊ณ  ํ•ด์„œ ๋ฌด์กฐ๊ฑด ์†Œ์ˆ˜์ธ ๊ฒƒ์€ ์•„๋‹˜. (ํ™•๋ฅ ์  ์†Œ์ˆ˜)
// ๊ทธ๋Ÿฌ๋‚˜ ํŠน์ • ์ˆ˜๋“ค์— ๋Œ€ํ•ด (checker ๋ฐฐ์—ด) ๋ชจ๋‘ ๊ฒ€์‚ฌํ•œ๋‹ค๋ฉด, ํ™•์ •์ ์œผ๋กœ ์†Œ์ˆ˜์ž„์„ ํŒ๋ณ„๊ฐ€๋Šฅ.
// (log n)^3 ์•Œ๊ณ ๋ฆฌ์ฆ˜
bool MR(ull N, ull A) {
ull d = N - 1;
while (d % 2 == 0) {
if (powmod(A, d, N) == N - 1) {
return true;
}
d /= 2;
}
ull tmp = powmod(A, d, N);
if (tmp == N - 1 || tmp == 1) { // a^(d*2^r) mod n = -1 ํŒ์ • ํ•˜๋Š” ๋ถ€๋ถ„์ž„
return true;
} else {
return false;
}
}
bool isPrime(ull N) {
if (N <= 1) {
return false;
} else if (N == 2) {
return true;
} else if (N <= 10'000'000'000ULL) { // ๊ธฐ์กด ๋ฐฉ๋ฒ•์ด ๋น ๋ฅธ ๊ตฌ๊ฐ„ + ๋ฐ€๋Ÿฌ๋ผ๋นˆ checker ์ˆ˜๋ณด๋‹ค ์ž‘์€ ๊ตฌ๊ฐ„
for (ull i = 3ULL; i * i <= N; i += 2) { // ํ™€์ˆ˜๋งŒ ๊ฒ€์‚ฌํ•œ๋‹ค.
if (N % i == 0ULL) return false; // ๋‚˜๋ˆ„์–ด ๋–จ์–ด์ง€๋ฉด, ์†Œ์ˆ˜
}
return true;
} else {
for (int i = 0; i < 7; i++) { // 7: checker size
ull A = checker[i];
if (MR(N, A) == false) {
return false;
}
}
return true;
}
}

์—๋ผ์Šคํ† ํ…Œ๋„ค์Šค์˜ ์ฑ„(Sieve)

Slow version

vector<int> getPrimes int MAX) {
vector<int> memo(MAX + 1, 0);
vector<int> res;
for(int i = 2; i <= MAX; ++i) {
if (memo[i] != 0) continue;
res.push_back(i);
for(int j = i; j <= MAX; j += i) {
memo[j] = 1;
}
}
return res;
}

Fast version

vector<int> getPrimes(int MAX) {
vector<int> memo(MAX + 1, 0);
vector<int> res;
int i;
for(i = 2; i * i <= MAX; ++i) {
if (memo[i] != 0) continue;
res.push_back(i);
for(int j = i * i; j <= MAX; j += i) {
memo[j] = 1;
}
}
for(; i <= MAX; ++i)
if (memo[i] == 0)
res.push_back(i);
return res;
}

Linear Sieve

  • sp ์— ๋“ค์–ด์žˆ๋Š” ํ•ด๋‹น ์ˆซ์ž์˜ ์ œ์ผ ์ž‘์€ ์†Œ์ธ์ˆ˜๋Š” ๋ค์ด๋‹ค.
vector<int> getPrimes(int MAX) {
vector<int> sp(MAX + 1, 0);
vector<int> res;
for(int i = 2; i <= MAX; ++i) {
if (sp[i] == 0) res.push_back(i);
for(auto& j: res) {
if (i * j > MAX) break;
sp[i * j] = j;
if (i % j == 0) break; // ์ด๋ฏธ ์ฒด๋กœ ๊ฑธ๋Ÿฌ์กŒ์œผ๋ฏ€๋กœ ๋”์ด์ƒ ๋ณด์ง€ ์•Š์Œ
}
}
return res;
}

Time Complexity

  • GCD: O(logโกA+logโกB)O(\log A + \log B)
    • ํ•œ๋ฒˆ ์žฌ๊ท€๋ฅผ ๋Œ ๋•Œ๋งˆ๋‹ค ์ ์–ด๋„ ์ˆ˜๊ฐ€ 12\frac 1 2์ด ๋˜๋ฏ€๋กœ, ๋กœ๊ทธ ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ ๋œ๋‹ค.
  • LCM: O(logโกA+logโกB)O(\log A + \log B)
    • GCD์— ๋‹ฌ๋ ค์žˆ๋‹ค.
  • Simple isPrime: O(N)O(\sqrt N)
  • ๋ฐ€๋Ÿฌ๋ผ๋นˆ isPrime: O(klogโก3N)O(k \log^3 N)
    • k๋Š” ํ…Œ์ŠคํŠธํ•ด์•ผํ•˜๋Š” ์ˆซ์ž์˜ ์ˆ˜
  • ์—๋ผ์Šคํ† ํ…Œ๋„ค์Šค์˜ ์ฑ„ ๊ตฌ์„ฑ: O(NlogโกlogโกN)O(N \log \log N)
  • Linear Sieve ๊ตฌ์„ฑ: O(N)O(N)