一、质数和合数
质数
如果一个数除了 1 1 1 和本身,没有其他的因数,就是质数。
合数
如果一个数除了 1 1 1 和本身,还有其他的因数,就是合数。
小贴士
1 1 1 是一个例外,既不是质数,也不是合数。
二、求质数程序
#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 = 50 100 \div 2 = 50 100÷2=50 |
2 | 50 ÷ 2 = 25 50 \div 2 = 25 50÷2=25 |
3 | 25 ÷ 5 = 5 25 \div 5 = 5 25÷5=5 |
4 | 5 ÷ 5 = 1 5 \div 5 = 1 5÷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;
}
程序问题:未遍历到 n n n 本身,然而在 n n n 是质数的情况下, n n n 这个数字本身也是 n n n 的质因数。
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;
}
程序问题: n n n 有可能是 1 1 1 ,然而 1 1 1 是一个例外,既不是质数,也不是合数。
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;
}
四、因数个数
由于输入的数字可能会超过 l o n g long long l o n g long long 的上限,为了保证万无一失,我们来找一找因数和质因数之间的关系。
以 100 100 100 举个例子。
因数 | 等价于 |
---|---|
1 1 1 | 2 0 × 5 0 2^0 \times 5^0 20×50 |
2 2 2 | 2 1 × 5 0 2^1 \times 5^0 21×50 |
4 4 4 | 2 2 × 5 0 2^2 \times 5^0 22×50 |
5 5 5 | 2 0 × 5 1 2^0 \times 5^1 20×51 |
10 10 10 | 2 1 × 5 1 2^1 \times 5^1 21×51 |
20 20 20 | 2 2 × 5 1 2^2 \times 5^1 22×51 |
25 25 25 | 2 0 × 5 2 2^0 \times 5^2 20×52 |
50 50 50 | 2 1 × 5 2 2^1 \times 5^2 21×52 |
100 100 100 | 2 2 × 5 2 2^2 \times 5^2 22×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、将数乘上任意一个非 0 0 0 正整数。
2、如果这个数是一个完全平方数,给它开根号。
现在小明想知道,在经过一系列操作以后,这个数最小可以变成多少?
输入描述
输入共一行,包含一个整数 n n n ( 2 ≤ n ≤ 5 × 1 0 8 2 \leq n \leq 5 \times 10^8 2≤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 = p k x=p^k x=pk 且是该数是 n n n 的因数,其中 p p p 是一个质数, k ≥ 1 k \geq 1 k≥1,将 n ÷ x n \div x n÷x 。
2、每次选取的数需要互不相同。
现在小明想知道,最多可以进行多少次这样的操作呢?
输入描述
输入共一行,包含一个整数 n n n ( 2 ≤ n ≤ 5 × 1 0 7 2 \leq n \leq 5 \times 10^7 2≤n≤5×107),表示初始数。
输出描述
输出一个整数,表示游戏过程中最多可以进行多少次操作。
样例1
输入
500
输出
3
样例解释
可以将 500 500 500 先除以 5 5 5 ,再除以 25 25 25 ,再除以 2 2 2 ,共执行 3 3 3 次。
参考代码
#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 | 输入一个整数 n n n |
12 | c n t cnt cnt 用来记录当前质因数的个数 |
13 | k k k 用来记录操作次数 |
14 | a n s ans ans 用来记录总操作次数 |
15 | 通过一个 f o r for for 循环从 2 2 2 开始遍历到 s q r t ( n ) sqrt(n) sqrt(n) |
17 | 通过一个 w h i l e while while 循环将 n n n 不断除以 i i i ,直到不能整除为止 |
19~23 | 记录下除以 i i i 的次数,并累加到 c n t cnt cnt 中 |
24 | 通过另一个 w h i l e while while 循环 |
26~27 | 从 1 1 1 到 c n t cnt cnt 遍历,每次将 k k k 累加,并将 c n t cnt cnt 减去k,直到 c n t cnt cnt 小于等于 0 0 0 为止 |
29 | 将最大操作次数加到 a n s ans ans 中( k − 1 k-1 k−1 就是当前质因数可以进行的最大操作次数) |
33~36 | 如果 n > 1 n>1 n>1,则说明剩下的 n n n 是一个新的质因数,将操作次数 + 1 +1 +1 |
37 | a n s ans ans 即游戏过程中最多可以进行的操作次数 |