HDU - 2588  GCD (数论,欧拉函数,gcd)

GCD

The greatest common divisor GCD(a,b) of two positive integers a and b,sometimes written (a,b),is the largest divisor common to a and b,For example,(1,2)=1,(12,18)=6. 
(a,b) can be easily found by the Euclidean algorithm. Now Carp is considering a little more difficult problem: 
Given integers N and M, how many integer X satisfies 1<=X<=N and (X,N)>=M.

Input

The first line of input is an integer T(T<=100) representing the number of test cases. The following T lines each contains two numbers N and M (2<=N<=1000000000, 1<=M<=N), representing a test case.

Output

For each test case,output the answer on a single line.

Sample Input

3
1 1
10 2
10000 72

Sample Output

1
6
260

题意:输入 N 和 M (2<=N<=1000000000, 1<=M<=N), 找出所有满足1<=X<=N 且 gcd(X,N)>=M 的 X 的数量.

思路:看见 gcd(X,N) >= M 很容易想到枚举 N 的大于 M 的因子。

一开始我在想,假设 X 是 N 中一个 >= M 的因子,那么 ans 直接  +=  N / X,也就是 X , 2 * X, .... N / X * X 与 N 的gcd肯定也 >= M,然后找到所有 >= M 的因子即可。但是你会发现,这样算是会有重复的。

比如 N = 12, M = 2,其中 3 倍的4 == 4 倍的3 ..

所以对于因子 X,ans 应该 += phi(N / X),这样也就相当于枚举所有可能的 gcdX(即 X),然后计算 gcd(y * X, N) == X 的 y 的个数(即 phi(N / X)),求和。

为什么是 ans += phi(N / X)?  假设数 A = p * d,B = q * d,那么 gcd(A,B) == d,且 p 一定与 q 互质,假如现在要找 gcd(A,C) == d,那么 C / d 一定与 p 互质,也就是 phi(p)

AC代码:

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define INT(t) int t; scanf("%d",&t)

using namespace std;

const int maxn = 2e5 + 10;
int phi[maxn];

int euler(int n){
    int ans = n;
    for(int i = 2;i * i <= n;++ i){
        if(n % i == 0){
            ans = ans / i * (i - 1);
            while(n % i == 0)
                n /= i;
        }
    }
    if(n > 1) ans = ans / n * (n - 1);
    return ans;
}

int main() {
    int t; scanf("%d",&t);
    while(t --){
        int n,m; scanf("%d%d",&n,&m);
        set<int> factor; factor.clear();
        for(int i = 1;i * i <= n;++ i){
            if(n % i == 0){
                if(i >= m)
                    factor.insert(n / i);
                if(n / i >= m)
                    factor.insert(i);
            }
        }
        int ans = 0;
        for(auto it : factor)
            ans += euler(it);
        cout << ans << endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值