Codeforces 1295 D. Same GCDs
Codeforces 1295 D. Same GCDs
题意:
给定两个整数\(a,m\leq10^{10}\)。
问有多少个\(0\leq x<m\)有\(gcd(a,m)=gcd(a+x,m)\)。
思路:
把结果写成表达式
\[\sum_{x=0}^{m-1}[gcd(a,m)=gcd(a+x,m)]
\]
根据gcd的计算过程有:
\[\sum_{x=0}^{m-1}[gcd(a,m)=gcd((a+x)mod\ m,\ m)]
\]
我们知道\(x\)的取值范围在\([0,m-1]\),其实就是相当于把\(a\)在数轴上向右平移了这么多个单位,取模之后又回到了\([0,m-1]\)的区间。
所以有
\[\sum_{i=0}^{m-1}[gcd(i,m)=gcd(a,m)]
\]
提取\(gcd(a,m)=d\)。
\[\sum_{i=0}^{m-1}[gcd(i,m)=g]\\\sum_{0\leq i<m}^{g|i}[gcd(\frac{i}{g},\frac{m}{g})=1]
\]
这个就是\(\varphi(\frac{m}{g})\)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a, m;
ll phi(ll x)
{
ll res = x;
for(ll i = 2; i <= x/i; i++)
{
if(x % i == 0)
{
res = res/i*(i-1);
while(x%i == 0) x /= i;
}
}
if(x > 1) res = res/x*(x-1);
return res;
}
ll gcd(ll a, ll b){
if(b == 0) return a;
return gcd(b, a%b);
}
void solve()
{
cin >> a >> m;
ll k = gcd(a, m);
cout << phi(m/k) << endl;
}
int main()
{
int T; scanf("%d", &T);
while(T--) solve();
}