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)$

数据范围:

$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;
}

  

原文地址:https://www.cnblogs.com/carcar/p/12259160.html