洛谷 P1029最大公约数和最小公倍数问题题解--zhengjun

题目描述

输入两个正整数 \(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\)

思路

题意应该很明确,就是找一对数,使它们的最小公约数是 \(x_0\) ,最大公倍数是 \(y_0\)
然后,还有一点,就是小学数学(我已经初一了)里面的一个公式:

\(x\times y=(\ x,y\ )\times [\ x,y\ ]\)

意思就是,两个数的最大公约数和最小公倍数的积就是这两个数的积

可以这样来理解:
A_zjzj

这样的话

\(x\times y=\) \((\)\(\times\)\()\) \(\times\) \((\)\(\times\)\()\)

\((\ n,m\ )\times [\ n,m\ ]=\)\(\times\) \((\)\(\times\)\(\times\)\()\)

这样就可以理解了,所以,只要枚举一个数,另一个数就可以算出来。

然后,求最大公约数还有一种很快的方法:辗转相除法

比如说求 \(391\)\(527\) 的最大公约数:
\(\ \ \ \ \ |391\ \ \ 527|\)
\(\underline{\ \ 0\ |0\ \ \ \ \ \ \ 391|\ 1\ }\)
\(\ \ \ \ \ |391\ \ \ 136|\)
\(\underline{\ \ 2\ |272\ \ \ 119|\ 1\ }\)
\(\ \ \ \ \ |119\ \ \ \ 17|\)
\(\underline{\ \ 7\ |119\ \ \ \ \ \ \ \ |\ \ \ \ }\)
\(\ \ \ \ \ |0\ \ \ \ \ \ \ \ \ \ \ |\)

这样除到 \(0\) 为止

证明:

假设 \(x\) , \(y\) 的最大公约数就是 \(k\)

\(k|x\ mod\ y\),问题就转换成了求 \(y\)\(x\ mod\ y\) 的最大公约数

以此类推,无论怎么模,余数始终是 \(k\) 的倍数,这样一步步算下来,最后当余数为 \(0\) 时, \(x\) 就是这两个数的最大公约数

这样,所有问题就都解决了

代码

#include<bits/stdc++.h>
using namespace std;
int m,n,ans;
int zj(int x,int y)//不要在意这个函数名
{
	int z;
    while(y!=0){//辗转相除法
    	z=x%y;
    	x=y;
    	y=z;
	}
	return x;
}
int main()
{
    cin>>n>>m;
    for(register int i=n;i<=m;i++)//因为P,Q一定比最大公约数大,比最小公倍数小
        if(n*m%i==0&&zj(i,n*m/i)==n)//符合要求
		    ans++;
    cout<<ans;
    return 0;
}

谢谢--zhengjun

posted @ 2022-06-10 19:03  A_zjzj  阅读(130)  评论(0编辑  收藏  举报