题目链接
题目描述
给定多次询问,每次输入一个正整数 ,输出欧拉函数
,即区间
内与
互质的整数个数。
解题思路
-
欧拉函数公式:若
的不同质因子集合为
,则
-
做法(试除分解质因子):
- 设答案
。从
开始试除,直到
。
- 一旦发现质因子
,就把
中的
全部除尽,并令
。
- 试除结束后,若剩余的
,说明
本身是一个质因子,同样令
。
- 设答案
-
边界:
时
。
为质数时
。
-
复杂度:单次询问试除到
,时间复杂度
,空间复杂度
。多次询问可逐个独立处理。
代码
#include <bits/stdc++.h>
using namespace std;
using int64 = long long;
// 计算单个整数的欧拉函数 φ(n)
static inline int64 phi(int64 n) {
if (n == 1) return 1; // 边界:φ(1) = 1
int64 ans = n;
for (int64 p = 2; p * p <= n; ++p) {
if (n % p == 0) {
// 将质因子 p 的幂全部除尽
while (n % p == 0) n /= p;
// 按公式 ans = ans / p * (p - 1)
ans = ans / p * (p - 1);
}
}
// 若此时 n > 1,说明剩余的是一个大于 sqrt(原始 n) 的质因子
if (n > 1) ans = ans / n * (n - 1);
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int q; // 询问次数
if (!(cin >> q)) return 0;
while (q--) {
long long n;
cin >> n;
cout << phi(n) << '\n';
}
return 0;
}
import java.util.*;
public class Main {
// 计算单个整数的欧拉函数 φ(n)
static long phi(long n) {
if (n == 1) return 1; // 边界处理
long ans = n;
for (long p = 2; p * p <= n; ++p) {
if (n % p == 0) {
while (n % p == 0) n /= p; // 去掉质因子 p 的所有幂
ans = ans / p * (p - 1); // 按公式更新答案
}
}
if (n > 1) ans = ans / n * (n - 1); // 处理剩余的大质因子
return ans;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int q = sc.nextInt();
while (q-- > 0) {
long n = sc.nextLong();
System.out.println(phi(n));
}
}
}
# 计算单个整数的欧拉函数 φ(n)
def phi(n: int) -> int:
if n == 1:
return 1 # 边界:φ(1) = 1
ans = n
p = 2
# 试除到 sqrt(n)
while p * p <= n:
if n % p == 0:
while n % p == 0:
n //= p # 去掉质因子 p 的所有幂
ans = ans // p * (p - 1) # 按公式更新答案
p += 1
# 若剩余 n > 1,则其为一个大质因子
if n > 1:
ans = ans // n * (n - 1)
return ans
q = int(input())
for _ in range(q):
n = int(input())
print(phi(n))
算法及复杂度
- 算法:分解
的不同质因子,按
更新答案。
- 时间复杂度:单次
。
- 空间复杂度:
。