前言:
数学符号约定:
-
\(p\) :任意一个质数
-
\(n\) 或 \(m\):任意一个正整数
-
\(a_i\):唯一分解时质数的指数
-
\(A\):集合
若无特殊说明,本篇题解的数学符号将会严格按照上述符号进行编写。
题目描述:
给定一个数 \(n\),求出至少两个数,使得他们的最小公倍数为 \(n\),且相加最小。
题目分析:
首先,我们浅浅的思考一下,很容易得出一个结论,多个数的最小公倍数其实就是他们唯一分解后每个质数的最小幂的乘积。打个比方,比如对于 \(12\) 和 \(30\) 来说,对他们分别进行唯一分解后,得出的结果分别是:
\[12=2^2\times 3^1 \]\[30=3^2 \times 5^1 \]所以他们的最小公倍数就是:
\[\operatorname{lcm}(12,30)=2^2 \times 3^1 \times 5^1 = 60 \]根据这个结论,我们可以反向思考,对一个数来说,其唯一分解出的每个质数幂所组成的集合中所有元素的最小公倍数必定是这个数,举个例子,对于 \(1890\) 来说,对其进行唯一分解后得出的结果为:
\[1890 = 2^1 \times 3^3 \times 5^1 \times 7^1 \]所以,分解出的每个质数幂所组成的集合 \(A\) 为:
\[A=\{2^1,3^3,5^1,7^1\} \]由此,我们不难看出,集合 \(A\) 中的所有元素的最小公倍数即为:
\[\operatorname{lcm}(A)=\operatorname{lcm}(2^1,3^3,5^1,7^1)=2^1 \times 3^3 \times 5^1 \times 7^1 =1890 \]现在,我们再思考另一个问题,对于多个大于 \(1\) 且两两不同的正整数来说,如何在他们的乘积不变的情况下相加最小。
首先,对于两个正整数 \(n\) 和 \(m\) (\(n\) 和 \(m\) 都大于 \(1\),且保证 \(n\) 和 \(m\) 不同)来说,我们可以十分轻易地看出来,\(n \times m\) 一定是大于 \(n + m\) 的。证明如下:
\[\begin{array}{r} (n-1)\times(m-1) > 1\\ n \times m - n - m + 1 > 1\\ n \times m - n - m >0\\ n \times m > n+m \end{array} \]所以,对于任意一个非质数幂合数 \(n\),若有多个整数的最小公倍数为它,则这些整数的和的最小值就应当为合数 \(n\) 唯一分解后的质数幂的和。
那么对于质数幂来说,就不适用上面的结论了,因为质数幂的唯一分解还是其本身,不满足题目条件“至少两个数”,解决方法也十分简单,如果一个数为质数幂,那么它的结果就应当是其本身加 \(1\)。
那么,问题又来了,我们需不需要判断他是不是质数幂呢,答案显然是不需要,我们只需要在唯一分解时,判断这个数是否只由一种质数组成即可。
代码实现:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int ResolveNumber(int n) { //唯一分解并求得答案。
int fin = sqrt(n);
int kinds = 0; //质数的种类个数。
int answer = 0;
for (int i = 2; i <= fin; i++) {
int power = 0;
if (n % i == 0) {
kinds++;
power = 1;
}
while (n % i == 0) {
n /= i;
power *= i;
}
answer += power;
}
if (n > 1) {
answer += n;
kinds++;
}
if (kinds == 1) //如果只有一种质数,则证明其为质数或质数幂,那我们就把结果加 1。
++answer;
return answer;
}
signed main() {
int cnt = 0;
while (1) {
int n;
cin >> n;
if (n == 0)
break;
if (n == 1) //特判一下 1。
printf("Case %lld: 2\n", ++cnt);
else
printf("Case %lld: %lld\n", ++cnt, ResolveNumber(n));
}
return 0;
}
标签:UVA10791,int,题解,质数,最小,times,公倍数,分解
From: https://www.cnblogs.com/larry76/p/16629368.html