[NOIP 2001 普及组] 最大公约数和最小公倍数问题

Starluo 发布于 28 天前 763 字 85 次阅读


题面

题目描述

输入两个正整数 $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

输入 #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$。

【题目来源】

NOIP 2001 普及组第二题

题解

一道数论题。

首先判断$x_0$是否为$y_0$的约数。如果不是,由最小公倍数的约数必定包含最大公约数可知,数对$P, Q$不可能存在,则输出$0$。

其次,我们考虑数对$P, Q$的生成方式。对$x_0, y_0$进行质因数分解,设为:

$x_0={p_1}^{m_1}*{p_2}^{m_2}*\cdots*{p_j}^{m_j}$

$y_0={p_1}^{m_1}*{p_2}^{m_2}*\cdots*{p_j}^{m_j}*{q_1}^{n_1}*{q_2}^{n_2}*\cdots*{q_k}^{n_k}$

其中$q_1, q_2, \cdots, q_k$可能与$p_1, p_2, \cdots, p_j$的部分或全部重合。

由题意,得到$P, Q$生成的如下约束条件:

①最大公约数是$x_0$,则$P, Q$的公约数不能出现除{p_1}^{m_1}, {p_2}^{m_2}, \cdots*, {p_j}^{m_j}及它们的低次幂以外的约数。

反例:$x_0=3, y_0=60$,构造了$P=6, Q=30$(将$y_0$的一个约数$2$转移给$x_0$),此时$P, Q$的最大公约数是$6$而非$3$。

②最小公倍数是$y_0$,则$P, Q$中均不可能出现除$p_i, q_i$以外的约数。

综上,我们可以得出数对$P, Q$的生成方式:

  • 前提:$(x_0, y_0)$是一组合法的$(P, Q)$。否则$(P, Q)$不存在。
  • 对$\frac{y_0}{x_0}$的结果进行质因数分解,得到

$\frac{y_0}{x_0}={q_1}^{n_1}*{q_2}^{n_2}*\cdots*{q_k}^{n_k}$

  • 将上式中的${q_i}^{n_i}$视为一组质因数,将完整的一组或多组质因数由$y_0$转移至$x_0$。
  • 因此,答案为$2^k$。(分步乘法原理:每一组质因数都有“转移”或“不转移”两种状态。)

完整代码如下。

#include<cstdio>
#include<cmath>
int x,y,cnt=0,s[100001],f=2;
bool p(int x)
{
	if(s[x]||x==2) return false;
	for(int i=2;i<=sqrt(x)+1;i++)
	{
		if(!(x%i)) return true;
	}
	s[x]=1; //质数判断结果记忆化
	return false;
}
int main()
{
	scanf("%d%d",&x,&y);
	if(y%x)
	{
		printf("0");
		return 0;
	}
	y/=x;
	while(y>1)
	{
		for(int i=f;i<=y;i++)
		{
			if(y%i||p(i)) continue;
			while(!(y%i)) y/=i;
			f=i; //质因数分解结果记忆化
			cnt++;
			break;
		}
	}
	printf("%d",1<<cnt); //等价于pow(2,cnt);
	return 0;
} 
此作者没有提供个人介绍。
最后更新于 2025-08-13