质因数分解写法
众所周知,大部分情况下我们(至少是我)都会使用以下这一种:
vector<pair<int, int> > v;
for (int i = 2; i * i <= n; i++)
{
int cnt = 0; // 计数:n有多少个为i的质因数
while (n % i == 0)
{
cnt++; // 存在一个
n /= i; // 把它除掉
}
v.push_back({i, cnt}); // 记录
}
if (n > 1)
{
v.push_back({n, 1}); // 注意最后n > 1的话需要记录
}
这种方法非常好写,还是\(O(\sqrt{n})\)的,但是我们会发现,如果我们想要速度,这种方法就不是最优了,因为如果\(i\)是个合数,那很明显不会参与到质因数的分解之中,但是我们还是遍历到了这些合数。所以如果想要加速,我们可以只遍历质数。
// 欧拉筛
int cc = 0;
for (int i = 2; i <= N; i++)
{
if (!b[i]) p[++cc] = i;
for (int j = 1; j <= cc && 1ll * i * p[j] <= N; j++)
{
b[i * p[j]] = true;
if (i % p[j] == 0) break;
}
}
vector<pair<int, int> > v;
for (int k = 1; 1ll * p[k] * p[k] <= n; k++) // 只枚举质数
{
int j = p[k];
int c = 0;
while (n % j == 0)
{
c++; //计数
n /= j; // 除掉
}
v.push_back({j, c}); // 记录
}
if (n > 1)
{
v.push_back({n, 1}); // 特判,记录
}
但是这样还会出现多余的质数,也就是说有些质数不是能分解出来的,但是还是遍历到的。
所以我们可以在欧拉筛的时候顺便把每个数字的最小的质因数(如果这个数字是质数,就是本身)求出来。
然后每次只要找到当前数字的这个最小的质因数,全部分解出来后继续找最小,直到这个数字\(=1\)停止。
代码:
int cc = 0;
for (int i = 2; i <= N; i++)
{
if (!b[i])
{
b[i] = i; // 质数的最小质因数为本身
p[++cc] = i;
}
for (int j = 1; j <= cc && 1ll * i * p[j] <= N; j++)
{
b[i * p[j]] = p[j]; // 第一个把这个数字给筛掉的质数就是最小质因数
if (i % p[j] == 0) break;
}
}
vector<pair<int, int> > v;
while (n > 1)
{
int j = b[n]; // 找到当前数字的最小质因数
int c = 0;
while (n % j == 0)
{
c++; // 计数
n /= j; // 除掉
}
v.push_back({j, c}); // 记录
}
// 因为我们已经确定了质数的最小质因数为本身,所以不需要再判断了。
在此,以此文章,铭记我因不会第3种分解质因数而与场切AT_abc445_e失之交臂。

浙公网安备 33010602011771号