C++知识点总结(11):质因子分解

一、质数和合数

质数

如果一个数除了 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 2n5×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;
}

代码思路:

  1. 输入一个整数n
  2. 通过一个for循环从2开始遍历到sqrt(n),如果n可以被i整除,则表明i是n的一个质因数,将其乘到ans中
  3. 通过一个while循环将n不断除以i,直到不能整除为止
  4. 如果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 k1,将 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 2n5×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 k1 就是当前质因数可以进行的最大操作次数)
33~36如果 n > 1 n>1 n>1,则说明剩下的 n n n 是一个新的质因数,将操作次数 + 1 +1 +1
37 a n s ans ans 即游戏过程中最多可以进行的操作次数
  • 17
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值