[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 \times b = \gcd(a,b)\times \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\times b}{\gcd(a,b)} = \operatorname{lcm}(a,b) \]

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

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

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

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

  1. 由于我们这里只枚举了\(i\)\(\sqrt{n\times 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\n",ans);
    return 0;
}

评测记录

AC 100R31075842

posted @ 2020-02-26 14:04  dbxxx  阅读(362)  评论(2编辑  收藏  举报