• [luogu p1029] 最大公约数和最小公倍数问题


    传送门

    题面

    题目描述

    输入两个正整数 (x_0, y_0),求出满足下列条件的 (P, Q) 的个数:

    1. (P,Q) 是正整数。
    2. 要求 (P, Q)(x_0) 为最大公约数,以 (y_0) 为最小公倍数。

    试求:满足条件的所有可能的 (P, Q) 的个数。

    输入输出格式

    输入格式

    一行两个正整数 (x_0, y_0)

    输出格式

    一行一个数,表示求出满足条件的 (P, Q) 的个数。

    输入输出样例

    输入样例 #1

    3 60
    

    输出样例 #1

    4
    

    说明

    (P,Q)(4) 种:

    1. (3, 60)
    2. (15, 12)
    3. (12, 15)
    4. (60, 3)

    对于 (100\%) 的数据,(2 le x_0, y_0 le {10}^5)

    分析

    考虑数论做法,废话数论试炼场里面当然是数论了,首先有定理:两个数的乘积等于它们最小公倍数和最大公约数的乘积。也就是:

    [a imes b = gcd(a,b) imes operatorname{lcm}(a,b) ]

    简证:
    首先我们知道,对于任意正整数(a,b),都有

    [gcd(dfrac{a}{gcd(a,b)},dfrac{b}{gcd(a,b)}) = 1 ]

    也就是(dfrac{a}{gcd(a,b)},dfrac{b}{gcd(a,b)})互质。原因很简单,如果它们不互质,就肯定有一个更大的公约数。
    这个时候就能得到:

    [dfrac{a imes b}{gcd(a,b)} = operatorname{lcm}(a,b) ]

    说实话,当年我见到这个式子我是完全蒙圈的,光看确实比较难理解。如果你自己在草稿纸上画一画,你就明白了大概了。刚刚说,(dfrac{a}{gcd(a,b)},dfrac{b}{gcd(a,b)})互质,也就是说最大公因数其实有一个显然的特征,两个数除以它们的最大公因数后互质。非常显然,(dfrac{a}{gcd(a,b)} imes b = dfrac{b}{gcd(a,b)} imes a = dfrac{a imes b}{gcd(a,b)})。还是因为(dfrac{a}{gcd(a,b)},dfrac{b}{gcd(a,b)})互质,所以三者不能在不破坏(a,b)的情况下同时做除法。此时(dfrac{a imes b}{gcd(a,b)} = operatorname{lcm}(a,b)),变形就可以得到(a imes b = gcd(a,b) imes operatorname{lcm}(a,b))了。

    举个例子吧,(4,6),它们的最大公因数是(2)。此时有(dfrac{4}{2} imes6 = dfrac{6}{2} imes4 = dfrac{4 imes6}{2}),也就是(2 imes6 = 3 imes4 = 12) 。此时不能在不破坏原数(4,6)的情况下同时做除法,所以(4,6)的最小公倍数是(12) 。但别忘了,这个(12)还有(dfrac{4 imes6}{2})的身份。这啥啊,这就是两个数的乘积除以最大公约数。两边同时( imes 2)(12 imes 2 = 4 imes 6)。 完美。

    证了这么半天的定理,有啥用吗?当然有了。我们可以考虑一种做法,枚举(i)(1 sim sqrt{n imes m}),通过(dfrac{n imes m}{i})求出另一个数,再判断这两个数的最大公因数是不是(m)即可,如果是ans++。轻松愉快兴奋激动。(?

    当然了还有一些注意事项:

    1. 由于我们这里只枚举了(i)(sqrt{n imes m}),但是题目中两个符合要求的数调换后会得到一个新的答案。所以这里我们最后要ans *= 2。当然了,如果你开心,也可以在循环过程中写ans += 2,也可以达到相同的效果。
    2. 小心(n = m) 情况。这种情况下会有一种答案,这种答案中的两个数相同,都为(n)。但是这种答案调换两个数后并不会得到一个新的答案,所以我们需要特判:if(n == m) ans--。注意这里可别写到ans *= 2之前,那样就相当于ans -= 2了。我差点掉进这个坑。

    代码

    代码实现比较简单。

    /*
     * @Author: crab-in-the-northeast 
     * @Date: 2020-02-26 12:49:17 
     * @Last Modified by: crab-in-the-northeast
     * @Last Modified time: 2020-02-26 14:01:06
     */
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    
    long long gcd(int a,int b) {
        return a % b ? gcd(b,a % b) : b;
    }
    
    int main() {
        int m,n;
        int ans = 0;
        scanf("%d%d",&m,&n);
    
        for(int i = 1; i <= sqrt(m * n);i++)
            if(n * m % i == 0 && gcd(i,n * m / i) == m)
                ans++;
        ans *= 2;
        if(n == m) ans--;
        printf("%d
    ",ans);
        return 0;
    }
    

    评测记录

    AC 100R31075842

  • 相关阅读:
    Java并发编程:线程池的使用
    Java并发(理论知识)—— 线程安全性
    grid
    grid
    grid
    grid
    grid
    grid
    grid
    grid
  • 原文地址:https://www.cnblogs.com/crab-in-the-northeast/p/luogu-p1029.html
Copyright © 2020-2023  润新知