1/*
2 * μ μλ‘ (Number Theory)
3 * GCD/LCM, μμ, λͺ¨λλ¬ μ°μ°, μ‘°ν©λ‘
4 *
5 * μνμ μκ³ λ¦¬μ¦μ κΈ°μ΄μ
λλ€.
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <stdbool.h>
11#include <string.h>
12#include <math.h>
13
14#define MOD 1000000007
15#define MAX_N 100001
16
17/* =============================================================================
18 * 1. GCD / LCM
19 * ============================================================================= */
20
21long long gcd(long long a, long long b) {
22 while (b) {
23 long long temp = b;
24 b = a % b;
25 a = temp;
26 }
27 return a;
28}
29
30long long gcd_recursive(long long a, long long b) {
31 if (b == 0) return a;
32 return gcd_recursive(b, a % b);
33}
34
35long long lcm(long long a, long long b) {
36 return a / gcd(a, b) * b;
37}
38
39/* νμ₯ μ ν΄λ¦¬λ μκ³ λ¦¬μ¦: ax + by = gcd(a, b) */
40long long extended_gcd(long long a, long long b, long long* x, long long* y) {
41 if (b == 0) {
42 *x = 1;
43 *y = 0;
44 return a;
45 }
46 long long x1, y1;
47 long long g = extended_gcd(b, a % b, &x1, &y1);
48 *x = y1;
49 *y = x1 - (a / b) * y1;
50 return g;
51}
52
53/* =============================================================================
54 * 2. μμ νλ³ λ° μ²΄
55 * ============================================================================= */
56
57bool is_prime(long long n) {
58 if (n < 2) return false;
59 if (n == 2) return true;
60 if (n % 2 == 0) return false;
61 for (long long i = 3; i * i <= n; i += 2) {
62 if (n % i == 0) return false;
63 }
64 return true;
65}
66
67/* μλΌν μ€ν
λ€μ€μ 체 */
68bool* sieve_of_eratosthenes(int n) {
69 bool* is_prime_arr = malloc((n + 1) * sizeof(bool));
70 memset(is_prime_arr, true, n + 1);
71 is_prime_arr[0] = is_prime_arr[1] = false;
72
73 for (int i = 2; i * i <= n; i++) {
74 if (is_prime_arr[i]) {
75 for (int j = i * i; j <= n; j += i) {
76 is_prime_arr[j] = false;
77 }
78 }
79 }
80 return is_prime_arr;
81}
82
83/* μ ν 체 (μμ λͺ©λ‘ μμ±) */
84int* linear_sieve(int n, int* prime_count) {
85 int* spf = calloc(n + 1, sizeof(int)); /* smallest prime factor */
86 int* primes = malloc((n + 1) * sizeof(int));
87 *prime_count = 0;
88
89 for (int i = 2; i <= n; i++) {
90 if (spf[i] == 0) {
91 spf[i] = i;
92 primes[(*prime_count)++] = i;
93 }
94 for (int j = 0; j < *prime_count && primes[j] <= spf[i] && i * primes[j] <= n; j++) {
95 spf[i * primes[j]] = primes[j];
96 }
97 }
98
99 free(spf);
100 return primes;
101}
102
103/* μμΈμλΆν΄ */
104typedef struct {
105 int prime;
106 int count;
107} PrimeFactor;
108
109int factorize(long long n, PrimeFactor factors[]) {
110 int count = 0;
111 for (long long d = 2; d * d <= n; d++) {
112 if (n % d == 0) {
113 factors[count].prime = d;
114 factors[count].count = 0;
115 while (n % d == 0) {
116 factors[count].count++;
117 n /= d;
118 }
119 count++;
120 }
121 }
122 if (n > 1) {
123 factors[count].prime = n;
124 factors[count].count = 1;
125 count++;
126 }
127 return count;
128}
129
130/* =============================================================================
131 * 3. λͺ¨λλ¬ μ°μ°
132 * ============================================================================= */
133
134long long mod_add(long long a, long long b, long long mod) {
135 return ((a % mod) + (b % mod)) % mod;
136}
137
138long long mod_sub(long long a, long long b, long long mod) {
139 return ((a % mod) - (b % mod) + mod) % mod;
140}
141
142long long mod_mul(long long a, long long b, long long mod) {
143 return ((a % mod) * (b % mod)) % mod;
144}
145
146/* λΉ λ₯Έ κ±°λμ κ³± */
147long long mod_pow(long long base, long long exp, long long mod) {
148 long long result = 1;
149 base %= mod;
150 while (exp > 0) {
151 if (exp & 1) {
152 result = mod_mul(result, base, mod);
153 }
154 base = mod_mul(base, base, mod);
155 exp >>= 1;
156 }
157 return result;
158}
159
160/* λͺ¨λλ¬ μμ (νλ₯΄λ§μ μμ 리, modκ° μμμΌ λ) */
161long long mod_inverse(long long a, long long mod) {
162 return mod_pow(a, mod - 2, mod);
163}
164
165/* λͺ¨λλ¬ μμ (νμ₯ μ ν΄λ¦¬λ) */
166long long mod_inverse_ext(long long a, long long mod) {
167 long long x, y;
168 long long g = extended_gcd(a, mod, &x, &y);
169 if (g != 1) return -1; /* μμ μμ */
170 return (x % mod + mod) % mod;
171}
172
173/* λͺ¨λλ¬ λλμ
*/
174long long mod_div(long long a, long long b, long long mod) {
175 return mod_mul(a, mod_inverse(b, mod), mod);
176}
177
178/* =============================================================================
179 * 4. μ‘°ν©λ‘ (Combinatorics)
180 * ============================================================================= */
181
182long long factorial[MAX_N];
183long long inv_factorial[MAX_N];
184
185void precompute_factorials(int n, long long mod) {
186 factorial[0] = 1;
187 for (int i = 1; i <= n; i++) {
188 factorial[i] = mod_mul(factorial[i - 1], i, mod);
189 }
190 inv_factorial[n] = mod_inverse(factorial[n], mod);
191 for (int i = n - 1; i >= 0; i--) {
192 inv_factorial[i] = mod_mul(inv_factorial[i + 1], i + 1, mod);
193 }
194}
195
196/* nCr (mod p) */
197long long nCr(int n, int r, long long mod) {
198 if (r < 0 || r > n) return 0;
199 return mod_mul(factorial[n], mod_mul(inv_factorial[r], inv_factorial[n - r], mod), mod);
200}
201
202/* nPr (mod p) */
203long long nPr(int n, int r, long long mod) {
204 if (r < 0 || r > n) return 0;
205 return mod_mul(factorial[n], inv_factorial[n - r], mod);
206}
207
208/* νμ€μΉΌμ μΌκ°ν (μμ nμ©) */
209long long** pascal_triangle(int n) {
210 long long** C = malloc((n + 1) * sizeof(long long*));
211 for (int i = 0; i <= n; i++) {
212 C[i] = calloc(n + 1, sizeof(long long));
213 C[i][0] = 1;
214 for (int j = 1; j <= i; j++) {
215 C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
216 }
217 }
218 return C;
219}
220
221/* =============================================================================
222 * 5. μ€μΌλ¬ νΌ ν¨μ
223 * ============================================================================= */
224
225long long euler_phi(long long n) {
226 long long result = n;
227 for (long long p = 2; p * p <= n; p++) {
228 if (n % p == 0) {
229 while (n % p == 0) n /= p;
230 result -= result / p;
231 }
232 }
233 if (n > 1) result -= result / n;
234 return result;
235}
236
237/* μ€μΌλ¬ νΌ μ²΄ */
238int* euler_phi_sieve(int n) {
239 int* phi = malloc((n + 1) * sizeof(int));
240 for (int i = 0; i <= n; i++) phi[i] = i;
241
242 for (int i = 2; i <= n; i++) {
243 if (phi[i] == i) { /* i is prime */
244 for (int j = i; j <= n; j += i) {
245 phi[j] -= phi[j] / i;
246 }
247 }
248 }
249 return phi;
250}
251
252/* =============================================================================
253 * 6. μ€κ΅μΈμ λλ¨Έμ§ μ 리 (CRT)
254 * ============================================================================= */
255
256/* x β‘ a1 (mod m1), x β‘ a2 (mod m2) */
257long long crt_two(long long a1, long long m1, long long a2, long long m2) {
258 long long x, y;
259 long long g = extended_gcd(m1, m2, &x, &y);
260
261 if ((a2 - a1) % g != 0) return -1; /* ν΄ μμ */
262
263 long long lcm_val = m1 / g * m2;
264 long long result = a1 + m1 * ((a2 - a1) / g % (m2 / g) * x % (m2 / g));
265 return ((result % lcm_val) + lcm_val) % lcm_val;
266}
267
268/* =============================================================================
269 * 7. μ½μ κ΄λ ¨
270 * ============================================================================= */
271
272int count_divisors(long long n) {
273 int count = 0;
274 for (long long i = 1; i * i <= n; i++) {
275 if (n % i == 0) {
276 count++;
277 if (i != n / i) count++;
278 }
279 }
280 return count;
281}
282
283long long sum_divisors(long long n) {
284 long long sum = 0;
285 for (long long i = 1; i * i <= n; i++) {
286 if (n % i == 0) {
287 sum += i;
288 if (i != n / i) sum += n / i;
289 }
290 }
291 return sum;
292}
293
294int* get_divisors(long long n, int* count) {
295 int* divisors = malloc(10000 * sizeof(int));
296 *count = 0;
297 for (long long i = 1; i * i <= n; i++) {
298 if (n % i == 0) {
299 divisors[(*count)++] = i;
300 if (i != n / i) divisors[(*count)++] = n / i;
301 }
302 }
303 return divisors;
304}
305
306/* =============================================================================
307 * ν
μ€νΈ
308 * ============================================================================= */
309
310int compare_int(const void* a, const void* b) {
311 return *(int*)a - *(int*)b;
312}
313
314int main(void) {
315 printf("============================================================\n");
316 printf("μ μλ‘ (Number Theory) μμ \n");
317 printf("============================================================\n");
318
319 /* 1. GCD / LCM */
320 printf("\n[1] GCD / LCM\n");
321 printf(" gcd(48, 18) = %lld\n", gcd(48, 18));
322 printf(" lcm(12, 18) = %lld\n", lcm(12, 18));
323
324 long long x, y;
325 long long g = extended_gcd(35, 15, &x, &y);
326 printf(" 35*%lld + 15*%lld = %lld (gcd)\n", x, y, g);
327
328 /* 2. μμ */
329 printf("\n[2] μμ νλ³ λ° μ²΄\n");
330 printf(" is_prime(17) = %s\n", is_prime(17) ? "true" : "false");
331 printf(" is_prime(18) = %s\n", is_prime(18) ? "true" : "false");
332
333 int prime_count;
334 int* primes = linear_sieve(50, &prime_count);
335 printf(" 50 μ΄ν μμ (%dκ°): ", prime_count);
336 for (int i = 0; i < prime_count; i++) printf("%d ", primes[i]);
337 printf("\n");
338 free(primes);
339
340 /* 3. μμΈμλΆν΄ */
341 printf("\n[3] μμΈμλΆν΄\n");
342 PrimeFactor factors[20];
343 int factor_count = factorize(360, factors);
344 printf(" 360 = ");
345 for (int i = 0; i < factor_count; i++) {
346 printf("%d^%d", factors[i].prime, factors[i].count);
347 if (i < factor_count - 1) printf(" Γ ");
348 }
349 printf("\n");
350
351 /* 4. λͺ¨λλ¬ μ°μ° */
352 printf("\n[4] λͺ¨λλ¬ μ°μ°\n");
353 printf(" 2^10 mod 1000 = %lld\n", mod_pow(2, 10, 1000));
354 printf(" 3^(-1) mod 7 = %lld\n", mod_inverse(3, 7));
355 printf(" κ²μ¦: 3 Γ %lld mod 7 = %lld\n", mod_inverse(3, 7),
356 mod_mul(3, mod_inverse(3, 7), 7));
357
358 /* 5. μ‘°ν©λ‘ */
359 printf("\n[5] μ‘°ν©λ‘ \n");
360 precompute_factorials(1000, MOD);
361 printf(" 10! = %lld\n", factorial[10]);
362 printf(" C(10, 3) = %lld\n", nCr(10, 3, MOD));
363 printf(" P(10, 3) = %lld\n", nPr(10, 3, MOD));
364
365 /* 6. μ€μΌλ¬ νΌ */
366 printf("\n[6] μ€μΌλ¬ νΌ ν¨μ\n");
367 printf(" Ο(12) = %lld\n", euler_phi(12));
368 printf(" Ο(13) = %lld (μμ)\n", euler_phi(13));
369
370 /* 7. μ½μ */
371 printf("\n[7] μ½μ\n");
372 printf(" 28μ μ½μ κ°μ: %d\n", count_divisors(28));
373 printf(" 28μ μ½μ ν©: %lld\n", sum_divisors(28));
374 int div_count;
375 int* divisors = get_divisors(28, &div_count);
376 qsort(divisors, div_count, sizeof(int), compare_int);
377 printf(" 28μ μ½μ: ");
378 for (int i = 0; i < div_count; i++) printf("%d ", divisors[i]);
379 printf("\n");
380 free(divisors);
381
382 /* 8. 볡μ‘λ */
383 printf("\n[8] 볡μ‘λ\n");
384 printf(" | μκ³ λ¦¬μ¦ | μκ°λ³΅μ‘λ |\n");
385 printf(" |-----------------|---------------|\n");
386 printf(" | GCD (μ ν΄λ¦¬λ) | O(log min) |\n");
387 printf(" | μμ νλ³ | O(βn) |\n");
388 printf(" | μλΌν μ€ν
λ€μ€ | O(n log log n)|\n");
389 printf(" | μμΈμλΆν΄ | O(βn) |\n");
390 printf(" | κ±°λμ κ³± | O(log exp) |\n");
391
392 printf("\n============================================================\n");
393
394 return 0;
395}