分解质因数

朴素的试除法

这里将从本质去分析这个简单的算法, 如果只是背模版, 请直接看代码, 或其他题解
算数的基本定理: 每个数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的趣味题]]

posted @ 2026-06-16 20:44  blind5883  阅读(10)  评论(0)    收藏  举报