D. Storming Arasaka(Codeforces 2238)

D. Storming Arasaka

题意简述

给定一个整数 n。考虑 n 的所有正因子,除了 1 以外都要分到若干层 L_1, L_2, ..., L_k

分层需要满足:

  1. 如果因子 x 在第 i 层,那么 x 的所有真因子,除了 1x 自己以外,都必须出现在更早的层;
  2. 每一层里的数可以排成一个序列,使得相邻两个数的 gcd 都大于 1

求最少需要多少层。

记号

设:

text 复制代码
n = p_1^{e_1} * p_2^{e_2} * ... * p_m^{e_m}

定义:

text 复制代码
Ω(n) = e_1 + e_2 + ... + e_m

表示质因子总个数,重复计算。

定义:

text 复制代码
ω(n) = m

表示不同质因子的个数。

本题答案是:

text 复制代码
Ω(n) + ω(n) - 1

为什么至少需要这么多层

1. 不同质数不能放在同一层

比如质数 23

它们的 gcd(2, 3) = 1,不能相邻。

更重要的是,如果某层里有质数 p,那么这一层不能再有任何 p 的倍数。因为那些倍数的真因子包含 p,按规则必须放在更早的层。

所以含有质数 p 的层只能放 p 自己。

因此所有不同质数必须分别占用一层:

text 复制代码
至少需要 ω(n) 层来放这些质数

设最后出现的那个质数在第 L 层,那么一定有:

text 复制代码
L >= ω(n)

2. 从这个质数走到 n 还要继续往后放

假设最后出现的质数是 p

p 开始,可以不断乘上剩余的质因子,形成一条因子链:

text 复制代码
p -> p * q_1 -> p * q_1 * q_2 -> ... -> n

这条链一共有 Ω(n) 个数。

因为后一个数以前一个数为真因子,所以它必须在更晚的层。

如果 p 在第 L 层,那么 n 至少要在:

text 复制代码
L + Ω(n) - 1

层。

又因为 L >= ω(n),所以:

text 复制代码
答案 >= Ω(n) + ω(n) - 1

为什么这么多层一定够

我们构造一种分层方法。

第一步,把所有不同质数分别单独放在前 ω(n) 层。

例如:

text 复制代码
L_1 = {p_1}
L_2 = {p_2}
...
L_m = {p_m}

第二步,从 s = 2Ω(n),把所有满足下面条件的因子放进同一层:

text 复制代码
这个因子的质因子总个数正好是 s

也就是:

text 复制代码
第 m + s - 1 层:所有 Ω(x) = s 的因子 x

条件 1 为什么满足

如果 yx 的真因子,那么:

text 复制代码
Ω(y) < Ω(x)

所以 y 一定在更早的层。

条件 2 为什么满足

同一层里所有数的质因子总个数都是同一个 s,并且 s >= 2

可以把一个因子看成一个"质因子袋子"。

例如:

text 复制代码
12 = 2 * 2 * 3

就是袋子:

text 复制代码
[2, 2, 3]

同一层的袋子大小都相同。我们可以按一种类似 Gray Code 的顺序排列这些袋子:每次只替换一个质因子,保留其它 s - 1 个质因子。

因为 s >= 2,相邻两个袋子至少还共享一个质因子,所以对应两个数的 gcd > 1

更直观地看:

text 复制代码
2*2*5  ->  2*3*5

它们都含有 25,所以 gcd > 1

因此同一层可以排成符合要求的链。

于是总层数正好是:

text 复制代码
ω(n) + (Ω(n) - 1) = Ω(n) + ω(n) - 1

结合前面的下界,这就是最优答案。

例子

n = 120

分解:

text 复制代码
120 = 2^3 * 3^1 * 5^1

所以:

text 复制代码
Ω(120) = 3 + 1 + 1 = 5
ω(120) = 3

答案:

text 复制代码
5 + 3 - 1 = 7

一种分层示意:

内容
1 5
2 3
3 2
4 质因子总个数为 2 的因子
5 质因子总个数为 3 的因子
6 质因子总个数为 4 的因子
7 120

n = 2^5 = 32

text 复制代码
Ω(32) = 5
ω(32) = 1
答案 = 5 + 1 - 1 = 5

这和样例输出一致。

算法流程

  1. 预处理 1..10^6 每个数的最小质因子;
  2. 对每个测试用例分解 n
  3. 统计:
    • totalPrimeFactors = Ω(n)
    • distinctPrimeFactors = ω(n)
  4. 输出:
text 复制代码
totalPrimeFactors + distinctPrimeFactors - 1

易错点

  1. Ω(n) 要重复计算质因子,例如 12 = 2^2 * 3,所以 Ω(12) = 3
  2. ω(n) 只计算不同质因子,例如 12 的不同质因子是 2, 3,所以 ω(12) = 2
  3. 答案不是约数个数,也不是最长整除链长度。最长整除链只给出 Ω(n),还要额外考虑不同质数不能在同一层。
  4. n 最大是 10^6,直接试除也可以,但预处理最小质因子更稳。

复杂度分析

预处理:

text 复制代码
时间复杂度:O(MAX log log MAX) 近似
空间复杂度:O(MAX)

每个测试用例分解:

text 复制代码
时间复杂度:O(log n)
空间复杂度:O(1)

其中 MAX = 10^6

C++ 代码实现

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    const int MAX_N = 1'000'000;
    vector<int> spf(MAX_N + 1, 0); // smallest prime factor,最小质因子

    for (int i = 2; i <= MAX_N; ++i) {
        if (spf[i] == 0) {
            for (long long j = i; j <= MAX_N; j += i) {
                if (spf[j] == 0) {
                    spf[j] = i;
                }
            }
        }
    }

    int T;
    cin >> T;

    while (T--) {
        int n;
        cin >> n;

        int totalPrimeFactors = 0;    // Ω(n):质因子总个数,重复计算
        int distinctPrimeFactors = 0; // ω(n):不同质因子个数

        int x = n;
        while (x > 1) {
            int p = spf[x];
            ++distinctPrimeFactors;

            while (x % p == 0) {
                x /= p;
                ++totalPrimeFactors;
            }
        }

        cout << totalPrimeFactors + distinctPrimeFactors - 1 << '\n';
    }

    return 0;
}
相关推荐
W是笔名1 小时前
python___容器类型的数据___列表
开发语言·windows·python
跨境数据猎手1 小时前
多平台电商比价系统从零搭建合规
开发语言·爬虫·架构
卷无止境1 小时前
SFML 深度解读:一个教科书级 C++ 多媒体库的内功心法
c++·后端
先吃饱再说1 小时前
一篇吃透树的遍历:递归与迭代的完整拆解
数据结构·算法
hai3152475431 小时前
九章编译法:DEEPSEEK V3.2汇编编译实例
java·开发语言
lkshop2 小时前
Next.js 网站 SEO 优化:从 SSR、Sitemap 到结构化数据
开发语言·javascript·ecmascript
Robot_Nav2 小时前
贪心算法、动态规划与 MPPI 算法结构相关力扣题目汇总
算法·贪心算法·动态规划
灯澜忆梦2 小时前
GO_函数_2
开发语言·golang·xcode
apihz3 小时前
经纬度制作高清卫星图片免费 API 接口详解
开发语言·ios·swift