Skip to content

Commit 6754db9

Browse files
committed
update phi-function.md add segmented totient
1 parent 7b91d9c commit 6754db9

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

src/algebra/phi-function.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,56 @@ void phi_1_to_n(int n) {
124124
phi[j] -= phi[i];
125125
}
126126
```
127+
### 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" }
128+
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.
129+
This implementation is based on the divisor sum property, but uses the [segmented sieve](sieve-of-eratosthenes.md#segmented-sieve) approach to compute the totient of all numbers between $L$ and $R$ in $O((R - L + 1) \log \log R)$.
130+
131+
```cpp
132+
const int MAX_RANGE = 1e6 + 6, MAX_R = 1e14;
133+
vector<int> primes;
134+
int phi[MAX_RANGE], rem[MAX_RANGE];
135+
136+
vector<int> linear_sieve(int n) {
137+
vector<bool> composite(n + 1, 0);
138+
vector<int> prime;
139+
140+
composite[0] = composite[1] = 1;
141+
142+
for(int i = 2; i <= n; i++) {
143+
if(!composite[i]) prime.push_back(i);
144+
for(int j = 0; j < prime.size() && i * prime[j] <= n; j++) {
145+
composite[i * prime[j]] = true;
146+
if(i % prime[j] == 0) break;
147+
}
148+
}
149+
return prime;
150+
}
151+
152+
/*
153+
* Find the totient of numbers from `L` to `R` with preprocess SQRT(MAX_R)
154+
* @note run linear_sieve(sqrt(MAX_R) + 1) at main
155+
* @note Complexity : O((R - L + 1) * log(log(R)) + sqrt(R))
156+
* @note phi(i) is phi[i - L] where i [L, R]
157+
*/
158+
void segmented_phi(int L, int R) {
159+
for(int i = L; i <= R; i++) {
160+
rem[i - L] = i;
161+
phi[i - L] = i;
162+
}
163+
164+
for(int &i : primes) {
165+
for(int j = max(i * i, (L + i - 1) / i * i); j <= R; j += i) {
166+
phi[j - L] -= phi[j - L] / i;
167+
while(rem[j - L] % i == 0) rem[j - L] /= i;
168+
}
169+
}
170+
171+
for(int i = 0; i < R - L + 1; i++) {
172+
if(rem[i] > 1) phi[i] -= phi[i] / rem[i];
173+
}
174+
}
175+
```
176+
127177

128178
## Application in Euler's theorem { #application }
129179

0 commit comments

Comments
 (0)