一、质数和合数
质数
如果一个数除了 111 和本身,没有其他的因数,就是质数。
合数
如果一个数除了 111 和本身,还有其他的因数,就是合数。
小贴士
111 是一个例外,既不是质数,也不是合数。
二、求质数程序
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
bool flag = true; // 默认 n 是质数
for (int i = 2; i <= sqrt(n); i++)
{
if (n % i == 0) // 如果 n 能整除 i
{
flag = false; // 标注 n 不是质数
break; // 跳出循环,因为已经知道 n 不是质数了
}
}
}
三、分解质因数
每个合数都可以写成几个质数相乘的形式,其中每个质数都是这个合数的因数,把每个质数都是这个合数的因数,把一个合数用质因数相乘的形式表示出来,叫做分解质因数。
有一种快速的分解质因数的方法,叫做短除法。简单来说,短除法就是不断地用最小的质因数除以它本身。
步骤 | 公式 |
---|---|
1 | 100÷2=50100 \div 2 = 50100÷2=50 |
2 | 50÷2=2550 \div 2 = 2550÷2=25 |
3 | 25÷5=525 \div 5 = 525÷5=5 |
4 | 5÷5=15 \div 5 = 15÷5=1 |
1. 初步推导
#include <iostream>
using namespace std;
int main()
{
// 输入
int n;
cin >> n;
// 分解质因数
for (int i = 2; i <= n; i++)
{
while (n % i == 0)
{
cout << i << " ";
n /= i;
}
}
return 0;
}
程序问题:运行超时。
2. 完善(1)
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
// 输入
int n;
cin >> n;
// 分解质因数
for (int i = 2; i <= sqrt(n); i++)
{
while (n % i == 0)
{
cout << i << " ";
n /= i;
}
}
return 0;
}
程序问题:未遍历到 nnn 本身,然而在 nnn 是质数的情况下, nnn 这个数字本身也是 nnn 的质因数。
3. 完善(2)
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
// 输入
int n;
cin >> n;
// 分解质因数
for (int i = 2; i <= sqrt(n); i++)
{
while (n % i == 0)
{
cout << i << " ";
n /= i;
}
}
// 特例
cout << n;
return 0;
}
程序问题: nnn 有可能是 111 ,然而 111 是一个例外,既不是质数,也不是合数。
4. 最终代码
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
// 输入
int n;
cin >> n;
// 分解质因数
for (int i = 2; i <= sqrt(n); i++)
{
while (n % i == 0)
{
cout << i << " ";
n /= i;
}
}
// 特例
if (n > 1)
{
cout << n;
}
return 0;
}
四、因数个数
由于输入的数字可能会超过 longlonglong longlonglong 的上限,为了保证万无一失,我们来找一找因数和质因数之间的关系。
以 100100100 举个例子。
因数 | 等价于 |
---|---|
111 | 20×502^0 \times 5^020×50 |
222 | 21×502^1 \times 5^021×50 |
444 | 22×502^2 \times 5^022×50 |
555 | 20×512^0 \times 5^120×51 |
101010 | 21×512^1 \times 5^121×51 |
202020 | 22×512^2 \times 5^122×51 |
252525 | 20×522^0 \times 5^220×52 |
505050 | 21×522^1 \times 5^221×52 |
100100100 | 22×522^2 \times 5^222×52 |
这样,我们写出代码:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
// 输入
long long n;
cin >> n;
// 分解质因数
long long cnt;
long long ans = 1; // 最终所有因数的个数
for (long long i = 2; i <= sqrt(n); i++)
{
cnt = 0;
while (n % i == 0)
{
cnt++;
n /= i;
}
ans *= (cnt+1);
}
// 特例
if (n > 1)
{
ans *= 2;
}
// 输出
cout << ans;
return 0;
}
五、数字游戏
题目描述
小明现在在进行一个数字游戏。在游戏中,给定一个初始数,可以对数字做以下两种操作任意次:
1、将数乘上任意一个非 000 正整数。
2、如果这个数是一个完全平方数,给它开根号。
现在小明想知道,在经过一系列操作以后,这个数最小可以变成多少?
输入描述
输入共一行,包含一个整数 nnn (2≤n≤5×1082 \leq n \leq 5 \times 10^82≤n≤5×108),表示初始数。
输出描述
输出一个整数,表示游戏过程中数最小可以变成多少。
样例1
输入
100
输出
10
样例解释
直接将100开根号,可以得到10。
参考代码
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
// 输入
int n;
cin >> n;
// 分解质因数
int ans = 1;
for (int i = 2; i <= sqrt(n); i++)
{
if (n % i == 0) // n 是质因数的时候
{
ans *= i;
}
while (n % i == 0)
{
n /= i;
}
}
// 特例
if (n > 1)
{
ans *= n; // n 是一个新的质因数
}
return 0;
}
代码思路:
- 输入一个整数n
- 通过一个for循环从2开始遍历到sqrt(n),如果n可以被i整除,则表明i是n的一个质因数,将其乘到ans中
- 通过一个while循环将n不断除以i,直到不能整除为止
- 如果n大于1,则说明剩下的n是一个新的质因数,将其乘到ans中。
六、数组游戏Ⅱ
题目描述
小明现在在进行一个数字游戏。在游戏中,给定一个初始数n,可以对数做以下操作任意次:
1、选择一个形如 x=pkx=p^kx=pk 且是该数是 nnn 的因数,其中 ppp 是一个质数,k≥1k \geq 1k≥1,将 n÷xn \div xn÷x 。
2、每次选取的数需要互不相同。
现在小明想知道,最多可以进行多少次这样的操作呢?
输入描述
输入共一行,包含一个整数 nnn (2≤n≤5×1072 \leq n \leq 5 \times 10^72≤n≤5×107),表示初始数。
输出描述
输出一个整数,表示游戏过程中最多可以进行多少次操作。
样例1
输入
500
输出
3
样例解释
可以将 500500500 先除以 555 ,再除以 252525 ,再除以 222 ,共执行 333 次。
参考代码
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
// 输入
int n;
cin >> n;
// 分解质因数
int cnt;
int k;
int ans = 0;
for (int i = 2; i <= sqrt(n); i++)
{
cnt = 0;
k = 1;
while (n % i == 0)
{
cnt++;
n /= i;
}
while (k <= cnt)
{
cnt -= k;
k++;
}
ans += (k-1);
}
// 特例
if (n > 1)
{
ans += 1;
}
cout << ans;
return 0;
}
代码详解
行数 | 功能 |
---|---|
8~9 | 输入一个整数 nnn |
12 | cntcntcnt 用来记录当前质因数的个数 |
13 | kkk 用来记录操作次数 |
14 | ansansans 用来记录总操作次数 |
15 | 通过一个 forforfor 循环从 222 开始遍历到 sqrt(n)sqrt(n)sqrt(n) |
17 | 通过一个 whilewhilewhile 循环将 nnn 不断除以 iii ,直到不能整除为止 |
19~23 | 记录下除以 iii 的次数,并累加到 cntcntcnt 中 |
24 | 通过另一个 whilewhilewhile 循环 |
26~27 | 从 111 到 cntcntcnt 遍历,每次将 kkk 累加,并将 cntcntcnt 减去k,直到 cntcntcnt 小于等于 000 为止 |
29 | 将最大操作次数加到 ansansans 中( k−1k-1k−1 就是当前质因数可以进行的最大操作次数) |
33~36 | 如果 n>1n>1n>1,则说明剩下的 nnn 是一个新的质因数,将操作次数 +1+1+1 |
37 | ansansans 即游戏过程中最多可以进行的操作次数 |