[ARC126C] Maximize GCD 题解

题意

给定一个序列 A,每次操作可以使 Ai+1i[1,n]K 次操作的 i 可以不同),最多可以做 K 次。问 gcdA1,A2,...,An 的最大值。

题解

首先,如果 K 可以把当前序列中所有的数都加到 Amax,那就全部加到 Amax,在此基础上同步对所有数相加即可。

如果 K 不足以把当前序列中所有的数都加到 Amax,那么可以发现最后的答案 AnsAmax,因为 Amax3×105,所以可以直接枚举判断当前答案是否成立。

可以把原题的条件进行转化

gcdA1,A2,...,An=AnsAnsA1,A2,...,An

又因为题目要求的是最大值,所以从大到小枚举即可。接下来考虑如何判定。

设当前枚举的答案是 x,那么对于序列中的数 Ai,它应当被加到 kxAi,考虑枚举 k 进行判定,使用前缀和记录序列中一定值域中的数的个数和和即可求解。

M=Amax,则最终的复杂度为 O(N+M×i=1M1i)=O(N+MlogM)

Code

#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;

class TreeArray {
public:
    typedef ValueVector container;
private:
    valueType size;
    container data;

    static valueType lowBit(valueType x) {
        return x & -x;
    }

public:
    explicit TreeArray(valueType n) : size(n), data(size + 1, 0) {};

    void insert(valueType pos, valueType key) {
        while (pos < size) {
            data[pos] += key;

            pos += lowBit(pos);
        }
    }

    valueType sum(valueType pos) const {
        valueType result = 0;

        while (pos > 0) {
            result += data[pos];

            pos -= lowBit(pos);
        }

        return result;
    }
};

constexpr valueType \maxA = 6e5 + 5;

int main() {
    std::ios_base::sync_with_stdio(false);

    valueType N, K;

    std::cin >> N >> K;

    if (N == 1) {
        valueType A;

        std::cin >> A;

        std::cout << (A + K) << std::endl;

        return 0;
    }

    ValueVector source(N);

    for (auto &iter: source)
        std::cin >> iter;

    TreeArray sum(\maxA), count(\maxA);

    valueType \max = 0;

    for (auto const &iter: source) {
        \max = std::\max(\max, iter);

        sum.insert(iter, iter);
        count.insert(iter, 1);
    }

    typedef std::function<bool(valueType)> CheckFunction;

    CheckFunction check = [\max, &sum, &count, K](valueType n) -> bool {
        valueType result = 0;

        for (valueType i = n; i <= \max + n; i += n)
            result += i * (count.sum(i) - count.sum(i - n)) - (sum.sum(i) - sum.sum(i - n));

        return result <= K;
    };

    valueType const minK = N * \max - sum.sum(\max);

    if (K >= minK) {
        std::cout << (\max + (K - minK) / N) << std::endl;
    } else {
        for (valueType i = \max; i >= 1; --i) {
            if (check(i)) {
                std::cout << i << std::endl;

                return 0;
            }
        }
    }
    return 0;
}
posted @   User-Unauthorized  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
点击右上角即可分享
微信分享提示