[算法学习记录] 因数分解、质因数分解、埃氏筛法

因数分解

如果要求一个数n的所有质因数,考虑到n = a * b,如果a<b,那么一定有$$a\leq\sqrt{n}\leq b$$考虑枚举a,那么b = n/a,相较于使用暴力枚举,这种方法可以显著降低时间复杂度。
例题 星码Starrycoding 【模板】求N的所有因子
本题就是一个因数分解的模版题,直接上代码:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e6+9;
//题目中数据量为1e12,,则最多有1e6个质因数
vector<ll> a;

void solve()
{
	ll n;cin >> n;
	for(ll i = 1;i * i <= n;i++)
	{
		if(n%i==0)
		{
			a.push_back(i);
			if(i != n / i)a.push_back(n / i);
		}	
	}
        //n = a*b;所以,只要枚举出一个a就能得到另一个b
	sort(begin(a),end(a));
        //按题目要求从小到大排序
	for(const auto &num : a)cout << num <<" ";
	cout << "\n";
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	while(_--)solve();
	return 0;
}

质因数分解

同样是找因数,不过这次多了一个限制条件,找质因数直接用循环暴力判断肯定是行不通的,所以我们要考虑其它方法。
根据唯一分解定理可知:对于任意N>1,都可以分解为若干质数的乘积,且分解方法唯一;我们可以利用这一特性,每当找到一个质因数,就一直用原数去除以这个质因数,直到除不尽,这样就可以动态缩小数据范围,以优化时间复杂度,代码实现如下:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
vector<ll> a;

void solve()
{
	ll n;cin >> n;
	for(ll i = 2;i * i<=n;i++)
	{
		if(n % i)continue;
		a.push_back(i);
		while(n % i == 0) n/=i;
	}

	a.push_back(n);
	//要记得把最后剩下的n也加进去,此时的n一定是一个质因数 

	for(auto &b : a)cout << b <<" ";
	cout << "\n";
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	while(_--)solve();
	return 0;
}

既然说到了质数,就在补充一个快速筛选一个区间内的质数的方法。

埃氏筛法

埃氏筛法是一种快速寻找某一区间的质数的算法,实现方法如下:

  1. 创建一个数组用来标记质数,默认初始化为0,并将0与1初始化为1(1为合数,0为质数);
  2. 从2开始遍历,每当找到一个值为0的坐标就把它的所有倍数标记为1,并重复此操作,直到完成筛选。
    代码实现如下:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e6 + 5;
bitset<N>vis;
//用来标记质数,1代表该数字为合数,0代表该数字为质数 

void solve()
{
	int n;cin >> n;
	vis[0] = 1,vis[1] = 1;
	//0,1一定不是质数 
	for(int i = 2;i <= n;i++)
	{
		if(!vis[i])
		{
			for(int j = 2;j*i<=n;j++)
			{
				vis[i * j] = 1;
			}
			//把所有倍数标记为1 
		}
	}
	
	for(int i = 2;i<=n;i++) if(!vis[i])cout << i <<" ";
	//输出 
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	while(_--)solve();
	return 0;
}

本人初学算法,能力有限,如有错误,敬请指正。

posted @ 2025-03-20 21:30  林克还是克林  阅读(369)  评论(0)    收藏  举报