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

本文介绍了质数和合数的概念,提供了C++程序示例来求解质数、分解合数以及计算因数个数,包括优化后的分解质因数方法和两个数字游戏的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、质数和合数

质数

如果一个数除了 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 不是质数了
        }
    }
}

三、分解质因数

每个合数都可以写成几个质数相乘的形式,其中每个质数都是这个合数的因数,把每个质数都是这个合数的因数,把一个合数用质因数相乘的形式表示出来,叫做分解质因数。

有一种快速的分解质因数的方法,叫做短除法。简单来说,短除法就是不断地用最小的质因数除以它本身。

步骤公式
1100÷2=50100 \div 2 = 50100÷2=50
250÷2=2550 \div 2 = 2550÷2=25
325÷5=525 \div 5 = 525÷5=5
45÷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 举个例子。

因数等价于
11120×502^0 \times 5^020×50
22221×502^1 \times 5^021×50
44422×502^2 \times 5^022×50
55520×512^0 \times 5^120×51
10101021×512^1 \times 5^121×51
20202022×512^2 \times 5^122×51
25252520×522^0 \times 5^220×52
50505021×522^1 \times 5^221×52
10010010022×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、如果这个数是一个完全平方数,给它开根号。
现在小明想知道,在经过一系列操作以后,这个数最小可以变成多少?

输入描述

输入共一行,包含一个整数 nnn2≤n≤5×1082 \leq n \leq 5 \times 10^82n5×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=pkx=p^kx=pk 且是该数是 nnn 的因数,其中 ppp 是一个质数,k≥1k \geq 1k1,将 n÷xn \div xn÷x
2、每次选取的数需要互不相同。
现在小明想知道,最多可以进行多少次这样的操作呢?

输入描述

输入共一行,包含一个整数 nnn2≤n≤5×1072 \leq n \leq 5 \times 10^72n5×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
12cntcntcnt 用来记录当前质因数的个数
13kkk 用来记录操作次数
14ansansans 用来记录总操作次数
15通过一个 forforfor 循环从 222 开始遍历到 sqrt(n)sqrt(n)sqrt(n)
17通过一个 whilewhilewhile 循环将 nnn 不断除以 iii ,直到不能整除为止
19~23记录下除以 iii 的次数,并累加到 cntcntcnt
24通过另一个 whilewhilewhile 循环
26~27111cntcntcnt 遍历,每次将 kkk 累加,并将 cntcntcnt 减去k,直到 cntcntcnt 小于等于 000 为止
29将最大操作次数加到 ansansans 中( k−1k-1k1 就是当前质因数可以进行的最大操作次数)
33~36如果 n>1n>1n>1,则说明剩下的 nnn 是一个新的质因数,将操作次数 +1+1+1
37ansansans 即游戏过程中最多可以进行的操作次数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值