Codeforces 1295D Same GCDs
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) \bmod 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[ \gcd\left(\dfrac i g , \dfrac m g \right) = 1 \right]$$
然后,左边的就是 $\left[1 , \dfrac m g \right)$ 的一段数,所以,这个就是:
$$ \sum_{i = 1}^{\frac m g - 1} \left[\gcd \left(i, \dfrac m g \right) = 1\right] $$
然后这个就是 $\varphi\left(\dfrac m g \right) = \varphi\left(\dfrac m {\gcd(a, m)} \right)$ 了。
#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; }