分解质因数
朴素的试除法
这里将从本质去分析这个简单的算法, 如果只是背模版, 请直接看代码, 或其他题解
算数的基本定理: 每个数N都可以唯一分解成一堆质数相乘的形式
即N = p1^b1 * p2^b2 * p3^b3 * ... * pk^bk;(p为质数)
分解质因数
和试除法判断质数有点像
按正常思路来就是[2, n]枚举每个数p, 看看哪个数p能整除它, 找到一个p就把n /= p, 不断进行这个操作, 记录操作次数
直到n % p != 0, 就把n里面可以分解出来的p全部除掉了, 就说明n里面可以分解出的p的个数, 找完了, 这时候p一定是质数
为什么p都是质数呢? 每个数n都可以唯一分解成一堆质数相乘的形式, 我们如果可以用p整除这个数n
那么p一定是质数, 因为如果p不是质数, 那么p就一定能分解成一堆质数, (因为是由p分解而来, 那么这些质数一定小于p)
这些质数一定在他之前我枚举过, 那么n中就不会再有这些质数(我全除干净了), p就一定不能整除n, 因此这样直接枚举的
可以整除n的p一定都是质数
当然这样是O(n)的, 很慢
我们设a / b = v, 这里是整除(a % b == 0), 我们从小到大枚举这个b, 并保证b <= v, 那么对于每个b都有一个对应的v(b == v时就是它自己)
那么b的极限就是 b * b == a, b = sqrt(a), 所以b <= sqrt(a), sqrt(a) <= v, v可能是质数, b也可能是质数, 例如a = 21, v = 7, b = 3; a = 28, b = 4, y = 7
而对于v是质数的情况v最多只有1个, 因为sqrt(a) <= v 如果有两个, a就一定撑不下,
所以我们可以[2, sqrt(a)]枚举b的个数, 如果最后n != 1说明还有剩的唯一的一个v, 再统计就好了
这样时间复杂度就是O(sqrt(n))
就可以用用了
代码很简单
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n, m;
int main()
{
int T;
cin >> T;
while (T -- )
{
cin >> n;
for (int i = 2; i <= n / i; i ++ ) // 只枚举前sqrt(n)就行了
{
if (n % i == 0)
{
int s = 0;
cout << i << ' ';
while (n % i == 0) n /= i, s ++ ;
cout << s << endl;
}
}
if (n != 1) cout << n << ' ' << 1 << endl; // 最后剩下的那个v, 要统计上
puts("");
}
return 0;
}
优化的思路
还有优化的空间, 上面也说了p一定是质数, 那么我们可以直接枚举质数这样就可以把时间优化到
O(sqrt(n) / ln(sqrt(n)))
优化例题[[AcWing 200. Hankson的趣味题]]

浙公网安备 33010602011771号