cf 1295D - Same GCDs
做法 :将问题化简为求区间内与x互质的数
令
x
=
a
+
x
,
g
c
d
(
a
,
m
)
=
d
,
a
=
k
1
d
,
m
=
k
2
d
,
x
=
k
3
d
x = a + x, gcd(a, m) = d, a = k_1d, m = k_2d, x = k_3d
x=a+x,gcd(a,m)=d,a=k1d,m=k2d,x=k3d,则
g
c
d
(
x
,
m
)
=
g
c
d
(
k
2
d
,
k
3
d
)
=
d
∗
g
c
d
(
k
2
,
k
3
)
=
d
gcd(x, m) = gcd(k_2d, k_3d) = d * gcd(k_2, k_3) = d
gcd(x,m)=gcd(k2d,k3d)=d∗gcd(k2,k3)=d,
故,
g
c
d
(
k
2
,
k
3
)
=
1
gcd(k_2, k_3) = 1
gcd(k2,k3)=1
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+10;
int p[N], cntp;
bool vis[N];
ll d[20], cntd;
ll a, m;
void sieve(int n) {
for(int i = 2; i <= n; i++) {
if(!vis[i]) p[cntp++] = i;
for(int j = 0; j < cntp && p[j] <= n / i; j++) {
vis[i * p[j]] = 1;
if(i % p[j] == 0) break;
}
}
}
int divide(ll x) {
cntd = 0;
for(int i = 0; x > 1 && i < cntp; i++) {
if(x % p[i] == 0) {
d[cntd++] = p[i];
while(x % p[i] == 0)
x /= p[i];
}
}
if(x > 1) d[cntd++] = x;
}
ll exgcd(ll a, ll b, ll& x, ll& y) {
if(!b) {
x = 1, y = 0;
return a;
}
ll res = exgcd(b, a%b, y, x);
y -= a/b * x;
return res;
}
ll rongchi(ll k) {
if(!k) return 0;
ll res = 0;
for(ll i = 0; i < (1<<cntd); i++) {
ll t = 1;
int cnt = 0;
for(int j = 0; j < cntd; j++) {
if(i & (1<<j)) t *= d[j], cnt++;
}
if(cnt&1) res -= k / t;
else res += k / t;
}
return res;
}
ll solve() {
ll x, y;
ll gcd =exgcd(a, m, x, y);
ll k1 = m / gcd, k2 = a/gcd;
divide(k1);
return rongchi(k2 + k1 - 1) - rongchi(k2-1);
}
int main() {
sieve(N-1);
int T;
scanf("%d", &T);
while(T -- ) {
scanf("%lld%lld", &a, &m);
printf("%lld\n",solve());
}
return 0;
}
(学了用容斥求区间内和x互质的数的写法,想想格雷码的生成方式,看看o(nlogn) 能不能优化成 o(n)。