#include <iostream>
#include <print>
#include <vector>
template<typename LowestPrime>
void sieve(int n, LowestPrime&& lowestPrime) {
std::vector<bool> isPrime(n + 1, true);
int i = 2;
for (; i * i <= n; ++i) {
if (!isPrime[i]) continue;
lowestPrime(i, i);
for (auto j = static_cast<int64_t>(i) * i; j <= n; j += i) {
if (isPrime[j]) {
lowestPrime(j, i);
isPrime[j] = false;
}
}
}
for (; i <= n; ++i) {
if (!isPrime[i]) continue;
lowestPrime(i, i);
}
}
template<typename LowestPrime>
void linearSieve(int n, LowestPrime&& lowestPrime) {
std::vector<int> primes;
std::vector<int> lowestPrimes(n + 1, 0);
for (int i = 2; i <= n; ++i) {
if (!lowestPrimes[i]) {
primes.push_back(i);
lowestPrimes[i] = i;
lowestPrime(i, i);
}
for (auto const& p: primes) {
if (p > lowestPrimes[i]) break;
if (auto j = static_cast<int64_t>(i) * p; j <= n) {
lowestPrimes[j] = p;
lowestPrime(j, p);
}
}
}
}
std::vector<int> computeMobius(int n) {
std::vector<int> lowestPrimes(n + 1);
sieve(n, [&](int i, int lowestPrime) {
std::println("lowestPrimes[{}] = {}", i, lowestPrime);
lowestPrimes[i] = lowestPrime;
});
std::vector<int> mobius(n + 1);
mobius[1] = 1;
for (int i = 2; i <= n; ++i) {
if (i == lowestPrimes[i]) {
mobius[i] = -1;
} else if (int j = i / lowestPrimes[i]; lowestPrimes[j] != lowestPrimes[i]) {
mobius[i] = -mobius[j];
} else {
mobius[i] = 0;
}
};
return mobius;
}
#include <chrono>
int main() {
int n = 100;
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
auto mobius = computeMobius(n);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl;
}