[CP / Codeforces] Codeforces Round 929 (Div. 3) A-E

最近不打算做新的题目了,先把之前打过的 contest 的题目都补完。我今天才发现,自己一直以来都陷入了这样一个误区,认为自己的水平还不够,经验积累得还不多,因此不能做高于 1900* 的题目……现在想来这个理由真是莫名其妙。如果不主动去做那些题,怎么积累相关的经验呢?

以上这些话与本文无关,只是想到了就写一写。


Codeforces Round 929 (Div. 3)

A. Turtle Puzzle: Rearrange and Negate

分析

\[ans=\sum\limits_{i=1}^{n}|a_i| \]

代码

void solve() {
    int n, t, ans = 0;
    std::cin >> n;
    for (int i = 0; i < n; i++) {
        std::cin >> t;
        if (t < 0)
            t = -t;
        ans += t;
    }
    std::cout << ans << '\n';
}

B. Turtle Math: Fast Three Task

分析

先对输入数组求和,记求和结果为 \(s\) ,分类讨论:

  • \(s\mod{}3=0\):直接输出 0。
  • \(s\mod{}3=1\):如果数组中存在元素 \(t\) 满足 \(3\ |\ (t-1)\),则去掉此元素就能使最后结果被 3 整除,所以输出 1;否则输出 2。
  • \(s\mod{}3=2\):对数组中的任意数加 1 就能使最后结果被 3 整除,所以输出 1。

代码

void solve() {
    int n, t, sum = 0;
    bool flag = false;
    std::cin >> n;
    for (int i = 0; i < n; i++) {
        std::cin >> t;
        if ((t - 1) % 3 == 0)
            flag = true;
        sum += t;
    }

    if (sum % 3 == 0)
        std::cout << "0\n";
    else if (sum % 3 == 2 || flag)
        std::cout << "1\n";
    else
        std::cout << "2\n";
}

C. Turtle Fingers: Count the Values of k

分析

因为数据范围不大,所以可以暴力枚举 \(x,y\) 所有可能的组合,然后判断是否满足 \(a^xb^y\ |\ l\),若满足则计算出 \(k=\frac{l}{a^xb^y}\) 并放入 unordered_set 中去重。

代码

void solve() {
    i64 l, a, b, ax = 1, by;
    std::cin >> a >> b >> l;

    std::unordered_set<int> ans;
    for (i64 x = 0; x <= 20; x++) {
        if (ax > l)
            break;
        by = 1;

        for (i64 y = 0; y <= 20; y++) {
            if (by > l)
                break;

            i64 m = ax * by;
            if (l % m == 0)
                ans.insert(l / m);

            by *= b;
        }

        ax *= a;
    }

    std::cout << ans.size() << '\n';
}

D. Turtle Tenacity: Continual Mods

分析

首先对输入数组从小到大排序。如果数组元素各异,那么可以直接从头到尾取余下去,因为每次取余的结果都比下一个数小,所以结果必然非零,并且等于第一次取余的结果;如果最小的元素重复,以 \([2,2,2,3,4,4,5,5,5,6,6]\) 为例,若按照先前的方法取余,一开始就会产生 \(0\),所以需要想办法让第一次取余的结果不被 2 整除。

因为

\[a \mod{} b=c < b \]

\[0 \mod{} a \equiv{} 0 \]

所以,只需要想办法在输入数组中找到一个数 \(k\) ,满足 \(k \mod{} 2 \neq{} 0\),以这个结果作为第一次取余的结果,再从头到尾取余下去,就不会产生 \(0\)

对于本例来说,可以取 \(3\) 作为这样的 \(k\),并将原数组安排为如下顺序:\([3,2,2,2,4,4,5,5,5,6,6]\),第一次取余将产生 \(1\),此结果之后不再发生变化。

代码

void solve() {
    int n, t;
    std::cin >> n;

    bool flag = true;
    std::map<int, int> m;
    for (int i = 0; i < n; i++) {
        std::cin >> t;
        ++m[t];
        if (flag && m[t] >= 2)
            flag = false;
    }

    if (flag || m.begin()->second == 1) {
        std::cout << "YES\n";
        return;
    }

    int p = m.begin()->first;
    for (const auto &[num, cnt] : m) {
        if (num % p != 0) {
            std::cout << "YES\n";
            return;
        }
    }

    std::cout << "NO\n";
}

E. Turtle vs. Rabbit Race: Optimal Trainings

分析

注意到我们寻找的目标随着下标的递增,具有先单调增,后单调减的性质,也就是所谓的极大值,故使用二分解决。

代码

void solve() {
    int n;

    std::cin >> n;
    std::vector<int> v(n + 1);
    for (int i = 1; i <= n; i++) {
        std::cin >> v[i];
        v[i] += v[i - 1];
    }

    int q, l, u, L, R, M;
    auto f = [&](int M) {
        int s1 = v[M] - v[l - 1];
        int s2 = v[M - 1] - v[l - 1];
        return 1LL * (2 * u + 1 - s1) * s1 > 1LL * (2 * u + 1 - s2) * s2;
    };

    std::cin >> q;
    for (int i = 0; i < q; i++) {
        std::cin >> l >> u;

        L = l + 1, R = n;
        while (L <= R) {
            M = (L + R) >> 1;
            if (f(M))
                L = M + 1;
            else
                R = M - 1;
        }
        std::cout << R << '\n';
    }
}
posted @ 2024-02-29 12:23  ZXPrism  阅读(38)  评论(0)    收藏  举报