codeforces#1295D. Same GCDs(数论/莫比乌斯)
题目链接:
https://codeforces.com/contest/1295/problem/D
题意:
给出$a$和$m$,在$0 \le x < m$,中多少个$x$满足 $\gcd(a, m) = \gcd(a + x, m)$
数据范围:
$1\leq a \leq 1e10$
$1\leq m \leq 1e10$
分析:
最暴力的写法,也就是在$\left [ \frac{a}{gcd(a,m)},\frac{a+m}{gcd(a,m)} \right ))$区间找到与$\frac{m}{gcd(a,m)}$互质数的个数
回忆莫比乌斯反演,1的$u$值为1,如果$x$由$k$个不互质数累乘,那么$u$值为$(-1)^{k}$,否则$u$值为0
那么枚举质数因子即可求出$u$值不为0的$x$和其$u$值(u为0那么对答案就没贡献了)
正解用到公式$\gcd(a, b) = \gcd(a - b, b)$,把题目转化为求$0 \le x < m$,中多少个$x$满足 $\gcd(a, m) = \gcd(x, m)$,所以答案是$phi(\frac{m}{gcd(a,m)})$
AC代码:
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
using namespace std;
const int maxn=1e5+7;
const int mod=1e9+7;
ll sk[30],cnt;
int main()
{
int T;
scanf("%d",&T);
while(T--){
ll a,m,ans=0;
cnt=0;
scanf("%lld %lld",&a,&m);
ll gd=__gcd(a,m);
ll st=a/gd,en=(a+m-1)/gd,x=m/gd;
//cout<<gd<<endl;
for(ll i=2;i*i<=x;i++){
if(x%i==0){
sk[++cnt]=i;
while(x%i==0)x/=i;
}
}
if(x!=1)sk[++cnt]=x;
int len=(1<<cnt);
// cout<<cnt<<" "<<gd<<endl;
for(int i=1;i<len;i++){
ll zz=1;
int u=1;
for(int j=1;j<=cnt;j++)
if((1<<(j-1))&i){
u*=-1;
zz*=sk[j];
}
// cout<<u<<" "<<(en/zz-(st-1)/zz)<<" "<<zz<<endl;
ans+=u*(en/zz-(st-1)/zz);
}
// cout<<ans<<endl;
ans+=en-st+1;
printf("%lld\n",ans);
}
return 0;
}

浙公网安备 33010602011771号