Bài toán
Nguồn: Codewars
Đọc hiểu
Với $n$ là tử số và $d$ là mẫu số, phân số được định nghĩa là tối giản nếu và chỉ nếu $GCD(n,d) = 1$.
Ví dụ, $\displaystyle\frac{5}{16}$ là phân số tối giản, trong khi $\displaystyle\frac{6}{16}$ không phải vì cả 6 và 16 đều chia hết cho 2 nên phân số rút gọn thành $\displaystyle\frac{3}{8}$
Cho một số $d$, hỏi có bao nhiêu phân số thực sự (phân số có tử bé hơn mẫu) tối giản nếu dùng $d$ làm mẫu số?
Ví dụ, cho $d = 15$: có tổng cộng 8 phân số thực sự tối giản mang giá trị từ 0 đến 1 là $$\displaystyle\frac{1}{15},\frac{2}{15},\frac{4}{15},\frac{7}{15},\frac{8}{15},\frac{11}{15},\frac{13}{15},\frac{14}{15}$$
Yêu cầu: xây dựng một hàm tính xem có bao nhiêu phân số thực sự tối giản với mẫu số đã cho:
properFractions(1) == 0
properFractions(2) == 1
properFractions(5) == 4
properFractions(15) == 8
properFractions(25) == 20
Và hàm phải xử lí được số lớn.
(proper
là do người ra đề viết nhầm với reduced
)
Lời giải
Chạy trâu
Bài toán có thể vét cạn: với mỗi số $n \leq d$ tính GCD của chúng đồng thời tăng biến đếm nếu GCD = 1. GCD (hay ước chung lớn nhất) của 2 số được tính bằng giải thuật Euclid.
long gcd(long a, long b) {
while(b){
int t = a % b;
a = b;
b = t;
}
return a;
}
long properFractions(long d)
{
int count = 0;
for(int n = 1; n < d; n++)
if(gcd(n,d) == 1)
count++;
return count;
}
Tuy nhiên, đề bài cho biết $d$ có thể là một số lớn nên phương pháp này không khả thi.
Hàm phi Euler
Vì bài toán chỉ xét các phân số thực sự ($n < d$) nên bài toán trở thành Tính hàm phi Euler của d
.
Trong lý thuyết số, hàm số Euler của một số nguyên dương $n$ được định nghĩa là số các số nguyên dương nhỏ hơn hoặc bằng $n$ nguyên tố cùng nhau với $n$. Hàm Euler được ký hiệu bởi $\phi (n)$ hoặc $\varphi (n)$, do đó hàm được gọi làm hàm phi Euler.
Wikipedia
Hàm phi Euler được tính bằng công thức: $$\begin{aligned} \phi(n) &= n \times (1 - \frac{1}{p_1}) \times (1 - \frac{1}{p_2}) \times…\times (1 - \frac{1}{p_k})\\ &= n\prod_{i=1}^k(1 - \frac{1}{p_i}) \end{aligned}$$
trong đó, $\ p_i$ là các thừa số nguyên tố khác nhau của $n$.
Kết hợp giải thuật phân tích thừa số nguyên tố của n với công thức trên, mình có được lời giải cho bài toán:
long properFractions(long n)
{
if(n == 1)
return 0;
long res = n;
for(long i = 2; i*i <= n; i++){
if(n % i == 0){
while (n % i == 0)
n /= i;
res -= res/i;
}
}
if (n > 1)
res -= res/n;
return res;
}
Cảm ơn bạn vì đã đọc