zoukankan      html  css  js  c++  java
  • Grakn Forces 2020

    比赛链接:https://codeforces.com/contest/1408

    A. Circle Coloring

    题意

    给出三个长为 $n$ 的序列 $a,b,c$,对于每个 $i$,$a_i e b_i, a_i e c_i, b_i e c_i$ 。

    构造序列 $p$,使得:

    • $p_i in {a_i, b_i, c_i}$
    • $p_i eq p_{(i + 1 mod n)}$

    题解

    即每个数不与前后两个数相同,因为三个序列同一位置两两不同,所以对于每个位置一定都有满足条件的数,枚举即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            vector<vector<int>> vec(3, vector<int> (n));
            for (auto &v : vec) {
                for (auto &x : v) {
                    cin >> x; 
                }
            }
            vector<int> p(n);
            for (int i = 0; i < n; i++) {
                for (auto &v : vec) {
                    if (v[i] != p[(i - 1 + n) % n] and v[i] != p[(i + 1) % n]) {
                        p[i] = v[i];
                        break;
                    }
                }
            }
            for (int i = 0; i < n; i++) {
                cout << p[i] << " 
    "[i == n - 1];
            }
        }
        return 0;
    }

    B. Arrays Sum

    题意

    给出一个大小为 $n$ 的非递减序数组 $a$ 和一个正整数 $k$ 。

    构造 $m$ 个非递减序数组 $b_1, b_2, ldots, b_m$,要求:

    • 每个 $b_i$ 大小为 $n$
    • $a_i = b_{1, i} + b_{2, i} + ldots + b_{m, i}$
    • 每个 $b_i$ 中最多有 $k$ 个不同的数 

    找出 $m$ 的最小值。

    题解

    设 $a$ 中有 $x$ 个不同的数,答案即 $1 + lceil frac{x - k}{k - 1} ceil$ 。

    因为 $b_1$ 可以包含 $a$ 中前 $k$ 个不同的数,之后的 $b_i$ 因为要用 $0$ 维护前面已有的和,每次只能新加 $a$ 中 $k-1$ 个不同的数。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) {
            int n, k;
            cin >> n >> k;
            set<int> st;
            for (int i = 0; i < n; i++) {
                int x;
                cin >> x;
                st.insert(x);
            }
            if (k == 1) {
                cout << (st.size() == 1 ? 1 : -1) << "
    ";
                continue;
            }
            cout << 1 + max(0, (int(st.size()) - 2)) / (k - 1) << "
    ";
        }
        return 0;
    }

    C. Discrete Acceleration

    题意

    有一条公路从坐标 $0$ 到坐标 $l$ 长为 $l$ 米,初始时甲车在坐标 $0$ 处,乙车在坐标 $l$ 处。

    公路上有 $n$ 个加速点,两车初速度均为 $1m/s$,经过一个加速点增加 $1m/s$,计算两车多久相遇。

    题解

    计算两车到每个加速点的时间,两车会在甲更快到的加速点和乙更快到的加速点之间相遇。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout << fixed << setprecision(15);
        int t;
        cin >> t;
        while (t--) {
            int n, l;
            cin >> n >> l;
            vector<double> a(n + 2);
            a[0] = 0;
            a[n + 1] = l;
            for (int i = 1; i <= n; i++) {
                cin >> a[i];
            }
            vector<double> t1(n + 2), t2(n + 2);
            t1[0] = 0;
            t2[n + 1] = 0;
            for (int i = 1; i < n + 2; i++) {
                t1[i] = t1[i - 1] + (a[i] - a[i - 1]) / i;
            }
            for (int i = n; i >= 0; i--) {
                t2[i] = t2[i + 1] + (a[i + 1] - a[i]) / (n + 1 - i);
            }
            double ans = 0.0;
            for (int i = 1; i < n + 2; i++) {
                if (t1[i - 1] <= t2[i - 1] and t1[i] >= t2[i]) {
                    ans = max(t1[i - 1], t2[i]) + (a[i] - a[i - 1] - abs(t1[i - 1] - t2[i]) * (t1[i - 1] < t2[i] ? i : n + 2 - i)) / (n + 2);
                    break;
                }
            }
            cout << ans << "
    ";
        }
        return 0;
    }

    D. Searchlights

    题意

    在二维平面上给出 $n$ 个人和 $m$ 个探照灯的坐标 $(a,b)$ 和 $(c,d)$,每次操作可以选择:

    • 将所有人横坐标加一
    • 将所有人纵坐标加一

    问使得任一人都不在任一探照灯左下方的最少操作次数。

    题解

    对于第 $i$ 个人和第 $j$ 个探照灯 ,如果 $dx + a_i ge c_j + 1$,那么他一定可以移出探照灯的范围,否则,对于所有小于 $dx = c_j - a_i + 1$ 的移动次数,它们对应的纵坐标移动次数至少要为 $d_j - b_i + 1$ 次才能移出该探照灯的范围。

    对于每个人枚举 $m$ 个探照灯,记录并更新每个横坐标移动次数对应的纵坐标移动次数的最大值,最后从后向前遍历并更新纵坐标的最大移动次数,因为如果之前移动了更多的横坐标仍需将纵坐标移动这么多次,那么对于现在移动了更少的横坐标也是必须的。

    $dp_i$ 的含义为横坐标移动次数为 $i$ 时,纵坐标的移动次数至少要为 $dp_i$ 才能保证所有人都移出探照灯的范围。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n, m;
        cin >> n >> m;
        vector<int> a(n), b(n);
        for (int i = 0; i < n; i++) {
            cin >> a[i] >> b[i];
        }
        vector<int> c(m), d(m);
        for (int i = 0; i < m; i++) {
            cin >> c[i] >> d[i];
        }
        constexpr int N = 1e6 + 10;
        vector<int> dp(N);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (a[i] <= c[j]) {
                    dp[c[j] - a[i]] = max(dp[c[j] - a[i]], d[j] + 1 - b[i]);
                }
            }
        }
        for (int i = N - 2; i >= 0; i--) {
            dp[i] = max(dp[i], dp[i + 1]);
        }
        int ans = INT_MAX;
        for (int i = 0; i < N; i++) {
            ans = min(ans, i + dp[i]);
        }
        cout << ans << "
    ";
        return 0;
    }

    E. Avoid Rainbow Cycles

    题意

    给出 $m$ 个集合 $A$,所有元素大小在 $[1,n]$ 之间。

    每个集合中的元素两两成边,颜色与集合相同,不同集合颜色不同。

    给出大小为 $m,n$ 的两个数组 $a,b$,从 $A_i$ 中移除值为 $j$ 的元素花费为 $a_i + b_j$ 。

    彩虹环指边颜色不重复的环,问使得图中无彩虹环的最少花费。 

    题解

    构造集合和数值的二分图,$A_i$ 与值为 $j$ 的元素间边权为 $a_i + b_j$,最少花费即为总边权和减去二分图的最大生成树。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    constexpr int N = 2e5 + 10;
    
    int fa[N];
    
    int Find(int x) {
        return fa[x] == x ? x : fa[x] = Find(fa[x]);
    }
    
    void Union(int x, int y) {
        x = Find(x);
        y = Find(y);
        if (x != y) {
            if (x < y) fa[y] = x;
            else fa[x] = y;
        }
    }
    
    void Init() {
        for (int i = 0; i < N; i++) {
            fa[i] = i;
        }
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        Init();
        int m, n;
        cin >> m >> n;
        vector<int> a(m);
        for (auto &x : a) cin >> x;
        vector<int> b(n);
        for (auto &x : b) cin >> x;
        long long sum = 0;
        vector<tuple<int, int, int>> edges; 
        for (int i = 0; i < m; i++) {
            int s;
            cin >> s;
            for (int j = 0; j < s; j++) {
                int x;
                cin >> x;
                --x;
                sum += a[i] + b[x];
                edges.emplace_back(a[i] + b[x], i + n, x);
            }
        }
        sort(edges.begin(), edges.end(), greater<>());
        for (auto [w, u, v] : edges) {
            if (Find(u) != Find(v)) {
                Union(u, v);
                sum -= w;
            }
        }
        cout << sum << "
    ";
        return 0;
    }

    F. Two Different

    题意

    给出一个大小为 $n$ 的数组 $a$,其中 $a_i = i$ 。

    每次操作可以选取两个元素并用二元映射函数 $f$ 赋值:$a_i = a_j = f(a_i,a_j)$ 。

    试给出一种操作方式,使得无论映射函数如何,最终 $a$ 中最多只有两个不同的数。

    题解

    如果数组大小为 $2^p$,那么最终可以都变为一个数。

    如:

    1. 1 2 3 4
    2. 5 5 6 6
    3. 7 7 7 7

    如果数组大小不为 $2^p$,对两个端点所在的 $2^p$ 长区间各操作一次即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        cin >> n;
        vector<pair<int, int>> ans;
        function<void(int, int)> dfs = [&](int l, int r) {
            if (l == r) return;
            int mid = (l + r) / 2;
            dfs(l, mid);
            dfs(mid + 1, r);
            for (int i = l, j = mid + 1; i <= mid; i++, j++) {
                ans.emplace_back(i, j);
            }
        };
        int p = 1 << __lg(n);
        dfs(1, p);
        if (p != n) {
            dfs(n - p + 1, n);
        }
        cout << ans.size() << "
    ";
        for (auto [x, y] : ans) {
            cout << x << ' ' << y << "
    ";
        }
        return 0;
    }

    参考博客

    https://blog.csdn.net/qq_45458915/article/details/108912813

  • 相关阅读:
    [luogu p2482] [SDOI2010]猪国杀
    [luogu p2296] 寻找道路
    左右布局(备用复制)
    导出Excel
    流式布局 及 媒体查询
    echarts设置(持续更新)
    解决Vue中watch首次进入路由不触发的问题
    Math.random
    Vue的拖拽
    使的dialog上下左右居中(弹框居中)
  • 原文地址:https://www.cnblogs.com/Kanoon/p/13768550.html
Copyright © 2011-2022 走看看