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;
}
posted @ 2020-01-31 09:42  syksykCCC  阅读(242)  评论(0编辑  收藏  举报