Description
描述
给出 $a$,$m$,求出 $0 le x < m$ 中,$gcd(a + x, m) = gcd(a, m)$ 的个数。
输入
第一行一个正整数 $T$($1 le T le 50$),表示数据组数。
接下来 $T$ 行,每行两个正整数 $a$ 和 $m$($1 le a, m le 10^{10}$)。
输出
每组数据一个数表示答案。
样例
输入
3
4 9
5 10
42 9999999967输出
6
1
9999999966解释
第一组数据:$x = 0, 1, 3, 4, 6, 7$ 可行。
第二组数据:$x = 0$ 可行。
Solution
题目是让我们求这个式子:
$$ sum_{x = 0}^{m - 1} [gcd(a, m) = gcd(a + x, m)] $$
然后,根据辗转相除法,我们可以把它转化为:
$$ sum_{x = 0}^{m - 1} [gcd(a, m) = gcd((a + x) mod m, m)] $$
右边就是把 $[0, m)$ 的区间向右平移了 $a$ 个单位,取模了以后显然还是 $[0, m)$ 的区间。
于是:
$$sum_{i = 0}^{m -1} [gcd(i, m) = gcd(a, m)]$$
令 $g = gcd(a, m)$,就是求:
$$sum_{i = 0}^{m-1} [gcd(i, m) = g]$$
$$ sum_{0 le i <m}^{g|i}left[ gcdleft(dfrac i g , dfrac m g
ight) = 1
ight]$$
然后,左边的就是 $left[1 , dfrac m g ight)$ 的一段数,所以,这个就是:
$$ sum_{i = 1}^{frac m g - 1} left[gcd left(i, dfrac m g ight) = 1 ight] $$
然后这个就是 $varphileft(dfrac m g ight) = varphileft(dfrac m {gcd(a, m)} ight)$ 了。
#include <bits/stdc++.h> using namespace std; typedef long long LL; LL gcd(LL a, LL b) { if(!b) return a; return gcd(b, a % b); } LL phi(LL x) { LL res = 1; for(LL i = 2; i * i <= x; i++) { if(x % i) continue; res *= i - 1; x /= i; while(x % i == 0) res *= i, x /= i; } if(x > 1) res *= x - 1; return res; } int main() { ios::sync_with_stdio(false); LL T; cin >> T; while(T--) { LL a, m; cin >> a >> m; cout << phi(m / gcd(a, m)) << endl; } return 0; }