5.【题解】Same GCDs

发布时间 2024-01-06 21:35:53作者: minecraft114514

题解

思路

  • 计算有多少个 \(x(0\leq x<m)\) 使得 \(\gcd(a,m)=\gcd(a+x,m)\)
  • 事实上就是求有多少个 \(x(1\leq x\leq m)\) 使得 \(\gcd(x,m)=\gcd(a,m)\)
  • 所以可以将 \(m\) 除以 \(\gcd(a,m)\) ,于是转化为求 \(m\) 的欧拉函数。
  • 所以只需要求 \(\varphi(m)\) 即可。

代码

#include<bits/stdc++.h>
#define ls (p<<1)
#define rs (p<<1|1)
#define endl '\n'
#define N (1000010)
#define int long long
using namespace std;
namespace IO
{
    #define ll long long
    const int MAX=1<<25;
    char buf[MAX],*p1=buf,*p2=buf;
    char obuf[MAX],*o=obuf;
    #define gc()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    //template<typename T>
    //inline T read()
    inline int read()
    {
        int x=0;bool f=1;
        char c=gc();
        for(;c<48||c>57;c=gc())if(c=='-')f=0;
        for(;c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c^48);
        return f?x:~x+1;
    }
    void print(ll x){if(x>9)print(x/10);*o++=(x%10)+'0';}
    void pit(ll x){if(x<0)*o++='-',x=~x+1;print(x);}
    void write(ll x,char end){pit(x);*o++=end;}
    void flush(){fwrite(obuf,o-obuf,1,stdout);}
    #undef ll
}
using IO::read;using IO::write;using IO::flush;
int n,m,t,P;
int x,y,k,ans,possible,lon;
int mod[N],a[N],gt[N],nth_mod[N];
int len,prime[700010];//,phi[N];//线性筛欧拉函数
bitset<N>vis;
int jc[N];
long long inv[N];//乘法逆元
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x<y?x:y;}
inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
int e[N],siz[N];
long long qpow(long long x,int b,int P=P)
{
    long long ans=1;
    for(;b;b>>=1){if(b&1)ans=(ans*x)%P;x=(x*x)%P;}
    return ans;
}//O(log(b))
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int exgcd(int a,int b,int &x,int &y)
{
    if(!b){x=1,y=0;return a;}
    int d=exgcd(b,a%b,y,x);
    y-=(a/b*x);
    return d;
}//O(max(a,b))
int ola(int n)
{
    int ans=n;
    for(int i=2;i*i<=n;++i)
    {
        if(n%i==0)ans=ans/i*(i-1);
        for(;n%i==0;n/=i);
    }
    if(n>1)ans=ans/n*(n-1);
    return ans;
}//O(sqrt(n))
void eular(int n)//欧拉筛
{
    //memset(vis,0,sizeof(vis));
    //phi[1]=1;
    for(int i(2);i<=n;++i)
    {
        if(!vis[i])
            prime[++len]=i;//,phi[i]=(i-1);
        for(int j(1);j<=len&&i*prime[j]<=n;++j)
        {
            vis[i*prime[j]]=1;
            /*
            if(!(i%prime[j]))
                {phi[i*prime[j]]=(phi[i]*prime[j]);break;}
            else phi[i*prime[j]]=(phi[i]*(prime[j]-1));
            */
        }
    }
}//O(n)
void niyuan1(int n,int P=P)//乘法逆元
{
    inv[1]=1;
    for(int i(2);i<=n;++i)inv[i]=((P-P/i)*inv[P%i])%P;
}//O(n)
int inv_it(int a,int P=P)//O(log(a))
{
    int d(exgcd(a,P,x,y));
    return(x%P+P)%P;
}
int C(int n,int m,int P=P)
{
    if(m>n)return 0;
    int a(1),b(1);
    for(int i(n-m+1);i<=n;++i)a=(a*i)%P;
    for(int i(2);i<=m;++i)b=(b*i)%P;
    return(a*qpow(b,P-2,P))%P;
}
int lucas(int n,int m,int P=P)
{return(!m)?1:(C(n%P,m%P,P)*lucas(n/P,m/P,P))%P;}
int exlucas_jc(int n,int now,int P=P)
{
    if(!n)return 1;
    int res(1);
    for(int i(1);i<=P;++i)//不含因子mod[now]
        if(i%mod[now])res=(res*i)%P;
    res=qpow(res,n/P,P);
    for(int i(1);i<=n%P;++i)if(i%mod[now])res=(res*i)%P;
    return(res*(exlucas_jc(n/mod[now],now,P)))%P;
}
int cal(int n,int m,int now,int P=P)
{
    int c1(exlucas_jc(n,now,P));
    int c2(exlucas_jc(m,now,P));
    int c3(exlucas_jc(n-m,now,P));
    int cnt(0);
    for(int i(n);i;i/=mod[now])cnt+=(i/mod[now]);
    for(int i(m);i;i/=mod[now])cnt-=(i/mod[now]);
    for(int i(n-m);i;i/=mod[now])cnt-=(i/mod[now]);
    return(((qpow(mod[now],cnt,P)*c1)%P*inv_it(c2,P))%P*inv_it(c3,P))%P;
}
int exlucas(int n,int m,int now,int P)
{return((inv_it(P/mod[now],mod[now])*(P/mod[now]))%P*cal(n,m,now,mod[now]))%P;}
int excrt(int n)//扩展中国剩余定理
{
    int mul(mod[1]);ans=a[1];
    int x,y,c,d;
    for(int i(2);i<=n;++i)
    {
        x=y=0;
        c=(a[i]-ans%mod[i]+mod[i])%mod[i];
        d=exgcd(mul,mod[i],x,y);
        if(!(c%d))
            ans+=(((x+mod[i])%mod[i])*(c/d)%mod[i])*mul,
            mul=mul*mod[i]/gcd(mul,mod[i]),
            ans%=mul;
        else return -1;
    }
    return ans%mul;
}
void solve_C(int n,int m)
{
    for(int i(1);i<=lon;++i)
        a[i]=(a[i]+lucas(n,m,mod[i]))%mod[i];
}
void init()
{
    P=read();
    n=read(),m=read();
    for(int i(1);i<=m;++i)gt[i]=read(),possible+=gt[i];
    if(possible>n)puts("Impossible"),exit(0);
    int PP(sqrt(P)),lsP(P);
    for(int i(2);i<=PP;++i)
    {
        if(!(lsP%i))mod[++lon]=i,lsP/=i,nth_mod[lon]=i;
        for(;!(lsP%i);lsP/=i)mod[lon]*=i;
    }//分解"只因"数
    if(lsP>1)mod[++lon]=lsP,nth_mod[lon]=lsP;//存在大于sqrt{n}的"只因"子
}
signed main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    for(int t=read();t;--t)
    {
        n=read(),m=read();
        write(ola(m/gcd(n,m)),'\n');
    }
    flush();
    return 0;
}