Grade 12 · Math for programmingCitește în română
Smallest-prime-factor sieve and fast factorization
Original: Ciur cu cel mai mic divizor prim și factorizare rapidă
The idea
A variant of the Sieve of Eratosthenes: instead of only marking 'composite', we store in dp[x] the smallest prime divisor of x. For every prime p (dp[p] still 0) we fill dp[p], dp[2p], dp[3p], ... where it is still 0. Then any x ≤ MAX is factorized very quickly: we repeatedly divide x by dp[x] and count how many times each prime appears. For q queries, the cost is a single sieve plus a few steps per query.
Original description (Romanian)
O variantă a ciurului lui Eratostene: în loc să marcăm doar „compus”, reținem în dp[x] cel mai mic divizor prim al lui x. Pentru fiecare prim p (dp[p] rămas 0) completăm dp[p], dp[2p], dp[3p], ... acolo unde încă e 0. Apoi orice x ≤ MAX se descompune foarte repede: împărțim repetat x la dp[x] și numărăm de câte ori apare fiecare prim. Pentru q întrebări, costul este un singur ciur plus câțiva pași pe întrebare.
- Complexity
- O(MAX log log MAX) for the sieve, O(log x) per factorization
- Grade
- Grade 12 (Clasa a XII-a)
- Chapter
- Math for programming
Examples
Input
4 360 97 1 1000000
Expected output
360 = 2^3 * 3^2 * 5 97 = 97 1 = 1 1000000 = 2^6 * 5^6
The code
Comments are in Romanian, as in the original collection. Edit freely: you can reset at any time.
/*
* Titlu: Ciur cu cel mai mic divizor prim și factorizare rapidă
* Clasa: 12
* Capitol: Matematică pentru programare
* Descriere: O variantă a ciurului lui Eratostene: în loc să marcăm doar „compus”,
* reținem în dp[x] cel mai mic divizor prim al lui x. Pentru fiecare
* prim p (dp[p] rămas 0) completăm dp[p], dp[2p], dp[3p], ... acolo unde
* încă e 0. Apoi orice x ≤ MAX se descompune foarte repede: împărțim
* repetat x la dp[x] și numărăm de câte ori apare fiecare prim. Pentru
* q întrebări, costul este un singur ciur plus câțiva pași pe întrebare.
* Complexitate: O(MAX log log MAX) pentru ciur, O(log x) pentru fiecare factorizare
*
* Exemplu
* Intrare:
* 4
* 360 97 1 1000000
* Ieșire:
* 360 = 2^3 * 3^2 * 5
* 97 = 97
* 1 = 1
* 1000000 = 2^6 * 5^6
*/
#include <iostream>
#include <vector>
using namespace std;
const int MAX = 1000000;
int main()
{
vector<int> dp(MAX + 1, 0); // dp[x] = cel mai mic divizor prim al lui x
for (int i = 2; i <= MAX; i++)
if (dp[i] == 0) // i este prim
for (int j = i; j <= MAX; j += i)
if (dp[j] == 0)
dp[j] = i;
int q;
cin >> q;
for (int t = 0; t < q; t++)
{
int x;
cin >> x;
cout << x << " = ";
if (x == 1)
{
cout << 1 << '\n';
continue;
}
bool primul = true;
while (x > 1)
{
int p = dp[x], e = 0;
while (x % p == 0)
{
x /= p;
e++;
}
if (!primul)
cout << " * ";
primul = false;
cout << p;
if (e > 1)
cout << '^' << e;
}
cout << '\n';
}
return 0;
}
Runs on a real g++ (C++17, -O2) through Compiler Explorer. Keep runs short; there's a time limit.