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;
}
相关推荐
魔力女仆18 分钟前
分享一个 JS 鼠标跟随贪吃蛇背景库
开发语言·javascript·计算机外设
2401_894915531 小时前
GEO 搜索优化完整源码从零部署:环境配置、集群搭建全流程
开发语言·python·tcp/ip·算法·unity
麻瓜老宋1 小时前
AI开发C语言应用按步走,表达式计算器calc的第二十二步,分号赋值链式修复、TOKEN_ASSIGN
c语言·开发语言·atomcode
普通网友2 小时前
共识算法实现:从工作量证明到权益证明的演进
算法·区块链·共识算法
颜x小3 小时前
[C#] C++与c#语法对比
开发语言·c++·c#
ldmd2843 小时前
地图生成算法(噪声篇-Perlin,Simplex,Value noise)
算法·go·地图生成
weixin_423652134 小时前
C#使用JObject
开发语言·c#
国科安芯4 小时前
FreeRTOS RISC-V 浮点上下文切换移植:在 IAR 工程中完整保存 FPU 寄存器
java·开发语言·单片机·嵌入式硬件·算法·系统架构·risc-v
小陈phd4 小时前
集成检索介绍
算法