质数
如果一个数除了 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 |
#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;
}
程序问题:运行超时。
#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 的质因数。
#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 是一个例外,既不是质数,也不是合数。
#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 即游戏过程中最多可以进行的操作次数 |