题目链接:
https://codeforces.com/contest/1295/problem/D
题意:
给出$a$和$m$,在$0 le x < m$,中多少个$x$满足 $gcd(a, m) = gcd(a + x, m)$
数据范围:
$1leq a leq 1e10$
$1leq m leq 1e10$
分析:
最暴力的写法,也就是在$left [ frac{a}{gcd(a,m)},frac{a+m}{gcd(a,m)} ight ))$区间找到与$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 ",ans); } return 0; }