公约数 欧拉函数 gcd

90 阅读1分钟

题目:3999. 最大公约数 - AcWing题库

视频解析:AcWing 3999. 最大公约数(每日一题)_哔哩哔哩_bilibili

思想

题目让我们求有多少个xx满足gcd(a,m)=gcd(a+x,m)gcd(a,m)=gcd(a+x,m)

我们定义dd(a,m)(a,m),(a+x,m)(a+x,m)的最大公约数,记作:

image.png

那么dd就能整除aa,且dd能整除mm,且dd可以整除xx

我们用aa'表示a/da/dmm'表示m/dm/d,x'表示x/dx/d。那么就有:

image.png

那么,现在问题就转化为了有多少个xx'是满足条件的。即有多少个xx'满足a+xa'+x'mm'是互质的。

因为题目说了0<x<m0<x<m,因此0<x<m0<x'<m

那么a+xa'+x'的范围就是[a',a'+m)。因此现在问题就转化为了求在[a',a'+m)范围内,与多少个x'满足a'+x'与m互质的数的个数。

我们发现[0,a']会和[m,a+m)[m,a'+m)这段在%m的情况下是等价的,比如0%m和m%m都等于0,0+1%m和m+1%m都等于1:

image.png

因此[a',a'+m)我们可以转化为[0,a']这一段,所以我们就变为了求[0,m)这段区间满足a'+x'与m互质的数的个数,也就是求与m互质的数个数,也就是求φ(m)\varphi(m)

image.png

code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b)
{
    return b?gcd(b,a%b):a;
}

LL phi(LL n)
{
    LL res=n;
    for(int i=2;i<=n/i;i++)
    {
        if(n%i==0)
        {
        res=res/i*(i-1);  //欧拉板子
        while(n%i==0)  n/=i;
        }//把i除尽
    }
    if(n>1)res=res/n*(n-1);  //大于根号n的因子
return res;
}
int main()
{
     int t;cin>>t;
     while(t--)
     {
        LL a,m;cin>>a>>m;
     
        
        //先求一下a,m最大公约数d
        LL d=gcd(a,m);
        
        //然后求0~m-1之间的互质数的个数
        LL ans=phi(m/d);
        
        printf("%lld\n",ans);
     }

    return 0;
}