|
| 1 | +/* |
| 2 | +*************************** |
| 3 | +* * |
| 4 | +* Author: Swaraj Deep * |
| 5 | +* * |
| 6 | +*************************** |
| 7 | +*/ |
| 8 | + |
| 9 | +#include <iostream> |
| 10 | +#include <vector> |
| 11 | +#include <array> |
| 12 | +#define ll long long |
| 13 | + |
| 14 | +using namespace std; |
| 15 | + |
| 16 | +// In this function we check for each possible divisor |
| 17 | +vector<pair<ll, ll>> trial_division(ll n) |
| 18 | +{ |
| 19 | + vector<pair<ll, ll>> factorization; |
| 20 | + for (ll d = 2; d * d <= n; ++d) |
| 21 | + { |
| 22 | + ll count = 0; |
| 23 | + while (n % d == 0) |
| 24 | + { |
| 25 | + n /= d; |
| 26 | + count++; |
| 27 | + } |
| 28 | + if (count) |
| 29 | + { |
| 30 | + factorization.push_back({d, count}); |
| 31 | + } |
| 32 | + } |
| 33 | + if (n > 1) |
| 34 | + { |
| 35 | + factorization.push_back({n, 1}); |
| 36 | + } |
| 37 | + return factorization; |
| 38 | +} |
| 39 | + |
| 40 | +// We first check 2 as a candidate so that we have to only consider 50% of the numbers (wheel factorization) |
| 41 | +vector<pair<ll, ll>> trial_division_optimized(ll n) |
| 42 | +{ |
| 43 | + vector<pair<ll, ll>> factorization; |
| 44 | + int count = 0; |
| 45 | + while (n % 2 == 0) |
| 46 | + { |
| 47 | + count++; |
| 48 | + n /= 2; |
| 49 | + } |
| 50 | + if (count) |
| 51 | + { |
| 52 | + factorization.push_back({2, count}); |
| 53 | + } |
| 54 | + for (ll d = 3; d * d <= n; d += 2) |
| 55 | + { |
| 56 | + count = 0; |
| 57 | + while (n % d == 0) |
| 58 | + { |
| 59 | + count++; |
| 60 | + n /= d; |
| 61 | + } |
| 62 | + if (count) |
| 63 | + { |
| 64 | + factorization.push_back({d, count}); |
| 65 | + } |
| 66 | + } |
| 67 | + if (n > 1) |
| 68 | + { |
| 69 | + factorization.push_back({n, 1}); |
| 70 | + } |
| 71 | + return factorization; |
| 72 | +} |
| 73 | + |
| 74 | +// The above approach can be extended i.e. if the number is not divisible by 3 then we ignore the multiples of 3 in the future computations. So we only need to check the numbers 5,7,11,13,17,19,23,.... We can observe a pattern of these remaining numbers. We need to check all numbers with d mod 6 = 1 and d mod 6 = 5. So this leaves us with only 33.3% percent of the numbers to check. |
| 75 | +vector<pair<ll, ll>> trial_division_more_optimized(ll n) |
| 76 | +{ |
| 77 | + vector<pair<ll, ll>> factorization; |
| 78 | + int count = 0; |
| 79 | + for (int d : {2, 3, 5}) |
| 80 | + { |
| 81 | + count = 0; |
| 82 | + while (n % d == 0) |
| 83 | + { |
| 84 | + count++; |
| 85 | + n /= d; |
| 86 | + } |
| 87 | + if (count) |
| 88 | + { |
| 89 | + factorization.push_back({d, count}); |
| 90 | + } |
| 91 | + } |
| 92 | + static array<int, 8> increments = {4, 2, 4, 2, 4, 6, 2, 6}; |
| 93 | + int i = 0; |
| 94 | + for (ll d = 7; d * d <= n; d += increments[i++]) |
| 95 | + { |
| 96 | + count = 0; |
| 97 | + while (n % d == 0) |
| 98 | + { |
| 99 | + count++; |
| 100 | + n /= d; |
| 101 | + } |
| 102 | + if (count) |
| 103 | + { |
| 104 | + factorization.push_back({d, count}); |
| 105 | + } |
| 106 | + if (i == 8) |
| 107 | + { |
| 108 | + i = 0; |
| 109 | + } |
| 110 | + } |
| 111 | + if (n > 1) |
| 112 | + { |
| 113 | + factorization.push_back({n, 1}); |
| 114 | + } |
| 115 | + return factorization; |
| 116 | +} |
| 117 | +// Extending the wheel factorization with more and more primes will leave exactly the primes to check. So a good way of checking is just to precompute all prime numbers with the Sieve of Eratosthenes until sqrt (n) and test them individually. |
0 commit comments