Codeforces Round 1000 (Div. 2)

A. Minimal Coprime

题目大意

给你一个区间lr,当lr互素的时候称为互素段,当lr范围内不包含其他互素段的时候称为极小互素段,问给定的区间内有多少个极小互素段

解题思路

显然连续奇偶构成的互素段就是极小互素段,因此只需要计算一下区间大小即可,需要特判r == 1的情况

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int t;
    std::cin >> t;

    while (t--) {
        int l, r;
        std::cin >> l >> r;

        std::cout << r - l + (r == 1) << "\n";
    }
}

B. Subsequence Update

题目大意

给你一个数组和一个lr区间,必须对数组的一个子序列进行翻转,然后让区间求和最小

解题思路

翻转前后都在lr区间之外的数字显然不会对最后的答案产生任何的影响,因此只需要考虑1-R和L-n两部分,然后让1-L和R-n尽可能小的部分换到区间内即可

代码实现

for _ in range(int(input())):
    n, l, r = map(int, input().split())
    l -= 1
    a = list(map(int,input().split()))
    b = a[:l] + sorted(a[l:])
    c = sorted(a[:r])[::-1] + a[r:]
    print(min(sum(b[l: r]), sum(c[l: r])))

C. Remove Exactly Two

题目大意

给你一棵树,让你删除两个割点,让树的连通块数量尽可能多

解题思路

看似只需要删除度最大的两个点,但是当他们相邻的时候可能会导致错误,一个简单的思路是枚举其中一个删除的节点,并更新其他节点度的数量,然后用multiset维护当前剩余节点中剩余度最多的边进行删除,最后对答案取max即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int t;
    std::cin >> t;

    while (t--) {
        int n, ans = 0;
        std::cin >> n;

        std::vector<int> in(n + 1);
        std::vector<std::vector<int>> g(n + 1, std::vector<int>());
        for (int i = 1; i < n; i++) {
            int u, v;
            std::cin >> u >> v;
            in[u]++;
            in[v]++;
            g[u].push_back(v);
            g[v].push_back(u);
        }

        std::multiset<int> mst;
        for (int i = 1; i <= n; i++) {
            mst.insert(in[i]);
        }

        for (int u = 1; u <= n; u++) {
            int sum = 1;
            mst.erase(mst.find(in[u]));
            for (auto v : g[u]) {
                mst.erase(mst.find(in[v]));
                mst.insert(in[v] - 1);
            }
            sum += in[u] - 1;
            sum += *mst.rbegin() - 1;
            for (auto v : g[u]) {
                mst.erase(mst.find(in[v] - 1));
                mst.insert(in[v]);
            }
            mst.insert(in[u]);
            ans = std::max(ans, sum);
        }

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

D. Game With Triangles

题目大意

给你两条平行线,线上各自有一些点,每次你可以选择三点来组成一个三角形,然后删除这三点,把你的分数加上这个三角形的面积,一直持续直到不能执行操作,问操作次数和每次执行操作后分数的最大值是多少,

解题思路

显然每次选平行线上最远的两点然后在另一根线上任选一点就是当前操作能得到的最大分数。假设在线a取i次一个点,则需要在线b取k-i次一个点,对两条线上的点分别求前缀和,可以快速预处理出选多少点分别能对答案(\(prea[i] + preb[k - i]\))贡献多少,显然答案函数是一个上凸函数,因此直接使用三分即可,注意三分边界,选的数量既不能小于0也不能大于点的数量

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int t;
    std::cin >> t;

    while (t--) {
        int n, m;
        std::cin >> n >> m;

        std::vector<int> a(n), b(m);
        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
        }
        for (int i = 0; i < m; i++) {
            std::cin >> b[i];
        }

        std::sort(a.begin(), a.end());
        std::sort(b.begin(), b.end());

        std::vector<i64> prea(n + 1), preb(m + 1);
        for (int i = 1; i <= n; i++) {
            prea[i] = prea[i - 1] + (a[n - i] - a[i - 1]);
        }
        for (int i = 1; i <= m; i++) {
            preb[i] = preb[i - 1] + (b[m - i] - b[i - 1]);
        }

        std::vector<i64> ans;
        for (i64 k = 1; std::max(0ll, 2 * k - m) <= std::min(k, n - k); k++) {
            int l = std::max(0ll, 2 * k - m), r = std::min(k, n - k);
            while (r - l > 2) {
                i64 mid1 = l + (r - l) / 3, mid2 = l + (r - l) * 2 / 3;
                if (prea[mid1] + preb[k - mid1] > prea[mid2] + preb[k - mid2]) {
                    r = mid2;
                } else {
                    l = mid1;
                }
            }

            i64 maxn = 0;
            for (int i = l; i <= r; i++) {
                maxn = std::max(maxn, prea[i] + preb[k - i]);
            }

            ans.push_back(maxn);
        }

        int kmax = ans.size();
        std::cout << kmax << "\n";
        for (int i = 0; i < kmax; i++) {
            std::cout << ans[i] << " \n"[i == kmax - 1];
        }
    }
}
posted @ 2025-02-05 01:14  udiandianis  阅读(105)  评论(0)    收藏  举报