diff --git a/src/algebra/phi-function.md b/src/algebra/phi-function.md index c69ee2841..c2ddbf937 100644 --- a/src/algebra/phi-function.md +++ b/src/algebra/phi-function.md @@ -94,7 +94,6 @@ void phi_1_to_n(int n) { } ``` - ## Divisor sum property { #divsum} This interesting property was established by Gauss: @@ -125,6 +124,53 @@ void phi_1_to_n(int n) { } ``` + +#### Finding the totient from $L$ to $R$ using the [segmented sieve](sieve-of-eratosthenes.md#segmented-sieve) { data-toc-label="Finding the totient from L to R using the segmented sieve" } +If we need the totient of all numbers between $L$ and $R$, we can use the [segmented sieve](sieve-of-eratosthenes.md#segmented-sieve) approach. + +The algorithm first precomputes all primes up to $\sqrt{R}$ using a [linear sieve](prime-sieve-linear.md) in $O(\sqrt{R})$ time and space; then for each number in the range $[L, R]$, it applies the standard φ formula $\phi(n) = n \cdot \prod_{p | n} \left(1 - \frac{1}{p}\right)$ by iterating over these primes while maintaining a `rem` array for the unfactored part—if `rem[i] > 1` after processing all small primes, it indicates a large prime factor greater than $\sqrt{R}$ handled in a final pass—so the range computation runs in $O((R - L + 1) \log \log R)$. To use this, call `primes = linear_sieve(sqrt(MAX_R) + 1)` once at startup; then `phi[i - L]` gives $\phi(i)$ for each $i \in [L, R]$. + + +```cpp +const long long MAX_RANGE = 1e6 + 6, MAX_R = 1e14; +vector primes; +long long phi[MAX_RANGE], rem[MAX_RANGE]; + +vector linear_sieve(int n) { + vector composite(n + 1, 0); + vector prime; + + composite[0] = composite[1] = 1; + + for(int i = 2; i <= n; i++) { + if(!composite[i]) prime.push_back(i); + for(int j = 0; j < prime.size() && i * prime[j] <= n; j++) { + composite[i * prime[j]] = true; + if(i % prime[j] == 0) break; + } + } + return prime; +} + +void segmented_phi(long long L, long long R) { + for(long long i = L; i <= R; i++) { + rem[i - L] = i; + phi[i - L] = i; + } + + for(long long &i : primes) { + for(long long j = max(i * i, (L + i - 1) / i * i); j <= R; j += i) { + phi[j - L] -= phi[j - L] / i; + while(rem[j - L] % i == 0) rem[j - L] /= i; + } + } + + for(long long i = 0; i < R - L + 1; i++) { + if(rem[i] > 1) phi[i] -= phi[i] / rem[i]; + } +} +``` + ## Application in Euler's theorem { #application } The most famous and important property of Euler's totient function is expressed in **Euler's theorem**: