1 条题解

  • 0
    @ 2025-8-24 21:15:16

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Maxmilite
    **

    搬运于2025-08-24 21:15:15,当前版本为作者最后更新于2023-08-12 10:44:52,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    Source & Knowledge

    2023 年 8 月语言月赛,由洛谷网校入门计划/基础计划提供。

    题目大意

    给定 nna1,a2,,ana _ 1, a _ 2, \cdots, a _ n。当 aa 序列中某两个元素相乘后是 147147154154 的倍数,所有 aia _ i 变为原来的两倍。求能否通过若干次(或 00 次)相乘,使得 a1+a2++anka _ 1 + a _ 2 + \cdots + a _ n \geq k

    题目分析

    本题考察较复杂的模拟。

    不难发现这样几条性质:

    1. 单个元素(n=1n = 1)一定无法反应。
    2. 如果两个元素 ai,aja _ i, a _ j 可以反应,那么它们就可以一直反应,使得序列无限翻倍。
    3. ai109a _ i \leq 10 ^ 9,那么 a1+a2++ana _ 1 + a _ 2 + \cdots + a _ n 不会超过 109×106=101510 ^ 9 \times 10 ^ 6 = 10 ^ {15}。那么,当 k>1015k > 10 ^ {15} 时,如果元素无法反应,那么一定无法达到目的。
    4. kk 的位数 17\geq 17 时,k1016k \geq 10 ^ {16},而 101610 ^ {16} 可以被 long long 容纳下。
    5. 154=2×7×11154 = 2 \times 7 \times 11。如果两个元素 ai,aja _ i, a _ j 乘积为 154154 的倍数,且这两个元素均不是 154154 的倍数,那么其中一个元素一定是 2×7=142 \times 7 = 142×11=222 \times 11 = 227×11=777 \times 11 = 77 的倍数,而另一个元素需要对应的是 11117722 的倍数。
    6. 147=3×7×7147 = 3 \times 7 \times 7。如果两个元素 ai,aja _ i, a _ j 乘积为 147147 的倍数,且这两个元素均不是 147147 的倍数,那么其中一个元素一定是 3×7=213 \times 7 = 217×7=497 \times 7 = 49 的倍数,而另一个元素需要对应的是 7733 的倍数。

    因此,对于每组数据,我们可以按照以下步骤处理:

    kk 的处理

    由性质 3 和性质 4,我们使用字符串 std::stringchar[] 读入 kk。读入后,首先判断 kk 的长度是否 17\geq 17。如果是,我们直接将整数类型的 kk 设为 101610 ^ {16};否则,我们手动模拟/使用库函数,将字符串类型的 kk 转换为整数类型。

    C++ 的 std::stoll() 可以将 std::string 转换为 long long 类型,这里使用这种方法进行转换。

    string s;
    cin >> s;
    if (s.length() < 17) {
        k = stoll(s);
    } else {
        k = 1e16;
    }
    

    n=1n = 1 的特殊处理

    对于 n=1n = 1,由于单个元素无法反应(性质 1),因此只需要判断仅有的一个元素 a1a _ 1kk 的大小关系。

    if (n == 1) {
        if (a[1] >= k) {
            cout << "Yes" << endl;
        } else {
            cout << "No" << endl;
        }
        continue;
    }
    
    

    直接判断当前元素是否总和 k\geq k

    我们只需读入时将所有元素相加,并与处理后的整数 kk 作比较,即可得到一个初步判断。

    找到可能反应的元素

    由性质 5 和性质 6,我们可以遍历一次数组,找到能够整除 14,22,77,21,4914, 22, 77, 21, 49 的元素。但是,对于另一个元素,如果我们再进行同样的遍历,时间复杂度为 O(n2)O(n ^ 2),不能接受。

    所以我们考虑分别记录能够整除 2,3,7,112, 3, 7, 11 的元素的数量。

    int cnt[15];
    int ops[] = { 2, 3, 7, 11 };
    memset(cnt, 0, sizeof(cnt));
    for (int i = 1; i <= n; ++i) {
        for (int j = 0 ; j < 4; ++j) {
            if (a[i] % ops[j] == 0) {
                ++cnt[ops[j]];
            }
        }
    }
    

    首先我们可以扫描查找是否有直接为 147147154154 的倍数的元素,如果有则直接输出 Yes,进行下一组数据的运算。

    如果没有,接下来,遍历数组查找能够整除 14,22,77,21,4914, 22, 77, 21, 49 的元素,并分别判断有多少能够整除 11,7,2,7,311, 7, 2, 7, 3 的元素。对于 14,22,77,4914, 22, 77, 49,只要有一个对应的另一个元素即可;但是对于 2121,由于 2121 本身可以整除 77,因此需要有至少两个对应的元素。

    int flag = 0;
    for (int i = 1; i <= n; ++i) {
        if (a[i] % 154 == 0 || a[i] % 147 == 0) { cout << "Yes" << endl; flag = 1; break; }
        if (a[i] % 21 == 0 && cnt[7] >= 2) { cout << "Yes" << endl; flag = 1; break; }
        if (a[i] % 49 == 0 && cnt[3]) { cout << "Yes" << endl; flag = 1; break; }
        if (a[i] % 77 == 0 && cnt[2]) { cout << "Yes" << endl; flag = 1; break; }
        if (a[i] % 14 == 0 && cnt[11]) { cout << "Yes" << endl; flag = 1; break; }
        if (a[i] % 22 == 0 && cnt[7]) { cout << "Yes" << endl; flag = 1; break; }
    }
    if (!flag)
        cout << "No" << endl;
    

    通过以上步骤,我们就可以完成所有判断。

    视频讲解

    视频题解后续将会上传。

    • 1

    [语言月赛 202308] 小粉兔的元素反应

    信息

    ID
    9043
    时间
    1000ms
    内存
    512MiB
    难度
    2
    标签
    递交数
    0
    已通过
    0
    上传者