求
∑
x
=
0
m
−
1
[
g
c
d
(
a
,
m
)
=
g
c
d
(
a
+
x
,
m
)
]
\sum_{x=0}^{m-1}[gcd(a,m)=gcd(a+x,m)]
∑x=0m−1[gcd(a,m)=gcd(a+x,m)]
由
g
c
d
(
a
,
m
)
=
g
c
d
(
a
+
0
,
m
)
,
g
c
d
(
a
,
m
)
=
g
c
d
(
a
+
m
,
m
)
gcd(a,m)=gcd(a+0,m),gcd(a,m)=gcd(a+m,m)
gcd(a,m)=gcd(a+0,m),gcd(a,m)=gcd(a+m,m)
所以原式:
=
∑
x
=
1
m
[
g
c
d
(
a
+
x
,
m
)
=
g
c
d
(
a
,
m
)
]
=\sum_{x=1}^{m}[gcd(a+x,m)=gcd(a,m)]
=x=1∑m[gcd(a+x,m)=gcd(a,m)]
=
∑
k
=
a
+
1
m
+
a
[
g
c
d
(
k
,
m
)
=
g
c
d
(
a
,
m
)
]
=\sum_{k=a+1}^{m+a}[gcd(k,m)=gcd(a,m)]
=k=a+1∑m+a[gcd(k,m)=gcd(a,m)]
由
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
%
b
)
gcd(a,b)=gcd(b,a\%b)
gcd(a,b)=gcd(b,a%b),可知
[
1
,
m
]
[1,m]
[1,m]中的结果会与
[
a
+
1
,
a
+
m
]
[a+1,a+m]
[a+1,a+m]中的结果一一对应起来。
因此有
=
∑
k
=
1
m
[
g
c
d
(
k
,
m
)
=
g
c
d
(
a
,
m
)
]
=\sum_{k=1}^{m}[gcd(k,m)=gcd(a,m)]
=k=1∑m[gcd(k,m)=gcd(a,m)]
令
g
=
g
c
d
(
a
,
m
)
g=gcd(a,m)
g=gcd(a,m),
=
∑
k
=
1
m
g
[
(
k
,
m
g
)
=
1
]
=
φ
(
m
g
)
=\sum_{k=1}^{\frac{m}{g}}[(k,\frac{m}{g})=1]=\varphi(\frac{m}{g})
=k=1∑gm[(k,gm)=1]=φ(gm)
质因子分解后求个欧拉函数即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define ll long long
const int N = 1e6+10;
ll p[N], prime[N], m;
ll index[N], tot;
void primes(ll n){
for(ll i = 2; i <= n; i++){
if(!p[i]) p[i] = i, prime[++m] = i;
for(ll j = 1; j <= m; j++){
if(prime[j] > p[i] || prime[j] > n/i) break;
p[i*prime[j]] = prime[j];
}
}
//for(ll i = 1; i <= 100; i++) cout << prime[i] << endl;
}
void fac_div(ll n){
tot = 0;
for(ll i = 1; i <= m && prime[i]*prime[i] <= n; i++){
if(n%prime[i] == 0){
index[++tot] = prime[i];
while(n%prime[i]==0) n/=prime[i];
}
if(n==1) break;
}
if(n>1) index[++tot] = n;
}
ll phi(ll n){
fac_div(n);
ll ans = n;
for(int i = 1; i <= tot; i++){
ans = ans/index[i]*(index[i]-1);
}
return ans;
}
int main(){
primes(1e6);
int t;
scanf("%d", &t);
// for(ll i = 1; i <= 20; i++) cout << phi(i) << endl;
while(t--){
ll a, n, ans = 0;
scanf("%lld%lld", &a, &n);
ans = phi(n/__gcd(a,n));
printf("%lld\n", ans);
}
return 0;
}