1 条题解

  • 0
    @ 2026-4-13 10:34:07

    题目题解:D. Turtle Tenacity: Continual Mods

    问题重述

    给定一个长度为 nn 的数组 aa,可以任意重排成 b1,b2,,bnb_1, b_2, \dots, b_n,判断是否存在一种排列使得:

    $$b_1 \bmod b_2 \bmod b_3 \bmod \dots \bmod b_n \neq 0 $$

    其中取模运算从左到右顺序执行。


    核心观察

    连续取模运算有一个重要性质:

    一旦某个中间结果变成 00,之后的所有取模结果都是 00

    因此,我们的目标是避免在运算过程中过早出现 00

    另一个重要性质:

    如果当前值为 xx,下一个模数为 yy,则 xmody<yx \bmod y < y。 特别地,如果 y>xy > x,则 xmody=xx \bmod y = x(值不变)。


    解题思路

    第一步:排序

    将数组按非递减顺序排序,得到:

    a1a2ana_1 \le a_2 \le \dots \le a_n

    第二步:检查最小值是否唯一

    情况 1: a1a2a_1 \neq a_2

    此时最小值是唯一的。我们可以将 a1a_1 放在序列的第一个位置:

    b=[a1,a2,a3,,an]b = [a_1, a_2, a_3, \dots, a_n]

    计算过程:

    • 第一步:a1moda2a_1 \bmod a_2
    • 因为 a1<a2a_1 < a_2(最小值唯一且排序后 a1<a2a_1 < a_2),所以 a1moda2=a1a_1 \bmod a_2 = a_1
    • 之后的所有数都 a2>a1\ge a_2 > a_1,因此 a1a_1 保持不变
    • 最终结果为 a1>0a_1 > 0

    结论: 当最小值唯一时,答案一定是 YES


    第三步:最小值不唯一的情况

    情况 2: a1=a2a_1 = a_2(最小值出现至少两次)

    此时不能简单地把最小值放在开头,因为:

    a1moda2=a1moda1=0a_1 \bmod a_2 = a_1 \bmod a_1 = 0

    一旦出现两个最小值相邻,就会得到 00

    但是,如果存在一个元素 axa_x 不是 a1a_1 的倍数,即:

    axmoda10a_x \bmod a_1 \neq 0

    则我们可以构造如下排列:

    $$b = [a_x, a_1, a_2, \dots, a_{x-1}, a_{x+1}, \dots, a_n] $$

    计算过程:

    • 第一步:axmoda1a_x \bmod a_1
    • 因为 axmoda1<a1a_x \bmod a_1 < a_1,记这个余数为 rr0<r<a10 < r < a_1
    • 接下来对 a1a_1 取模:rmoda1=rr \bmod a_1 = r(因为 r<a1r < a_1
    • 之后的所有数都 a1>r\ge a_1 > r,因此 rr 保持不变
    • 最终结果为 r>0r > 0

    结论: 当最小值不唯一,但存在一个不是最小值倍数的数时,答案是 YES


    第四步:所有元素都是最小值的倍数

    情况 3: a1=a2a_1 = a_2 且对所有 iiaimoda1=0a_i \bmod a_1 = 0

    此时数组中所有数都是 a1a_1 的倍数。

    无论怎么排列,至少有一个最小值不在第一位(因为最小值至少有两个)。考虑任意排列:

    • 第一个数记为 b1b_1
    • 当遇到第一个 a1a_1(最小值)时,有两种可能:
      1. 如果 b1b_1 也是 a1a_1 的倍数,则 b1moda1=0b_1 \bmod a_1 = 0,结果变成 00
      2. 如果 b1b_1 之前已经变成 00,那结果已经是 00

    更严格地证明:在序列中必然出现至少一次 xmoda1x \bmod a_1 的运算,其中 xxa1a_1 的倍数,结果必然是 00。之后所有取模结果都是 00

    结论: 当所有元素都是最小值的倍数时,答案是 NO


    算法流程

    sort(a, a + n);
    
    if (a[0] != a[1]) {
        // 最小值唯一
        cout << "YES\n";
    }
    else {
        // 最小值不唯一,检查是否存在不是 a[0] 倍数的数
        bool found = false;
        for (int i = 1; i < n; i++) {
            if (a[i] % a[0] != 0) {
                found = true;
                break;
            }
        }
        cout << (found ? "YES\n" : "NO\n");
    }
    

    复杂度分析

    • 时间复杂度:O(nlogn)O(n \log n),主要由排序贡献
    • 空间复杂度:O(1)O(1)O(n)O(n)(取决于是否使用额外数组)

    示例验证

    输入 排序后 判断 输出
    [1,2,3,4,5,6][1,2,3,4,5,6] 121\neq2 → YES YES
    [3,3,3,3,3][3,3,3,3,3] 全为3的倍数 → NO NO
    [2,2,3][2,2,3] 3%2=103\%2=1\neq0 → YES YES
    [1,1,2,3,7][1,1,2,3,7] 存在非1倍数 → YES(?实际输出NO,需注意) NO

    注意第4个样例:[1,1,2,3,7][1,1,2,3,7],最小值是 11,所有数都是 11 的倍数(因为任何数 mod1=0\bmod 1 = 0),所以实际上是 NO。


    总结

    判断条件可以简洁表述为:

    • YES 当且仅当:最小值唯一,或者存在一个不是最小值倍数的数
    • NO 当且仅当:最小值不唯一,且所有数都是最小值的倍数
    • 1

    信息

    ID
    6505
    时间
    1000ms
    内存
    256MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者