Codeforces 1295 D. Same GCDs

Codeforces 1295 D. Same GCDs

题意:

给定两个整数\(a,m\leq10^{10}\)

问有多少个\(0\leq x<m\)\(gcd(a,m)=gcd(a+x,m)\)

思路:

把结果写成表达式

\[\sum_{x=0}^{m-1}[gcd(a,m)=gcd(a+x,m)] \]

根据gcd的计算过程有:

\[\sum_{x=0}^{m-1}[gcd(a,m)=gcd((a+x)mod\ m,\ m)] \]

我们知道\(x\)的取值范围在\([0,m-1]\),其实就是相当于把\(a\)在数轴上向右平移了这么多个单位,取模之后又回到了\([0,m-1]\)的区间。

所以有

\[\sum_{i=0}^{m-1}[gcd(i,m)=gcd(a,m)] \]

提取\(gcd(a,m)=d\)

\[\sum_{i=0}^{m-1}[gcd(i,m)=g]\\\sum_{0\leq i<m}^{g|i}[gcd(\frac{i}{g},\frac{m}{g})=1] \]

这个就是\(\varphi(\frac{m}{g})\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a, m;
ll phi(ll x)
{
    ll res = x;
    for(ll i = 2; i <= x/i; i++)
    {
        if(x % i == 0)
        {
            res = res/i*(i-1);
            while(x%i == 0) x /= i;
        }
    }
    if(x > 1) res = res/x*(x-1);
    return res;
}

ll gcd(ll a, ll b){
    if(b == 0) return a;
    return gcd(b, a%b);
}

void solve()
{
    cin >> a >> m;
    ll k = gcd(a, m);
    cout << phi(m/k) << endl;
}

int main()
{
    int T; scanf("%d", &T);
    while(T--) solve();
}

posted @ 2020-02-05 04:13  zhaoxiaoyun  阅读(135)  评论(0编辑  收藏  举报