1. 问题描述:
给定两个正整数 a,m,其中 a < m。请你计算,有多少个小于 m 的非负整数 x 满足:gcd(a,m) = gcd(a + x,m)
输入格式
第一行包含整数 T,表示共有 T 组测试数据。每组数据占一行,包含两个整数 a,m。
输出格式
每组数据输出一行结果,一个整数,表示满足条件的非负整数 x 的个数。
数据范围
前三个测试点满足,1 ≤ T ≤ 10。
所有测试点满足,1 ≤ T ≤ 50,1 ≤ a < m ≤ 1010。
输入样例:
3
4 9
5 10
42 9999999967
输出样例:
6
1
9999999966
来源:https://www.acwing.com/problem/content/4002/
2. 思路分析:
对于这种最大公约数的题目一般都需要推导一下,可以发现x也是d的倍数,其中d为a,m的最大公约数,令x' = x / d,m' = m / d,a' = a / d,所以(a' + x',m') = 1也即求解有多少个x'满足要求,0 <= x' < m,0 <= x' < m',也即求解a'~a' + m - 1中有多少个数与m'互质,通过下图可以发现求解的其实是0~m'之间有m'互质的数的个数,求解某个欧拉函数值可以使用公式在O(√n)的时间复杂度内求解出来。
下面的第一个公式是算数基本定理,第二个公式是N的欧拉函数计算公式,我们可以通过O(√n)的时间复杂度求解出N的欧拉函数值,
3. 代码如下:
class Solution:
# 求解a和b的最大公约数
def gcd(self, a: int, b: int):
return a if b == 0 else self.gcd(b, a % b)
# 求解m的欧拉函数值(使用公式求解即可)
def phi(self, m: int):
res = m
i = 2
while i * i <= m:
if m % i == 0:
res = res // i * (i - 1)
# 将m中所有为i的因子除掉
while m % i == 0:
m //= i
i += 1
# m > 1的时候也是一个质因子
if m > 1:
res = res // m * (m - 1)
return res
def process(self):
T = int(input())
for c in range(T):
a, m = map(int, input().split())
d = self.gcd(a, m)
m //= d
print(self.phi(m))
if __name__ == '__main__':
Solution().process()