zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 218【A

    比赛链接:https://atcoder.jp/contests/abc218/tasks

    A - Weather Forecast

    题意

    判断一个字符串的第 (n) 个字符是否为 o

    题解

    模拟。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        cin >> n;
        string s;
        cin >> s;
        cout << (s[n - 1] == 'o' ? "Yes" : "No") << "
    ";
        return 0;
    }
    

    B - qwerty

    题意

    依次输出第 (x_i) 个小写字母。

    题解

    模拟。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        for (int i = 0; i < 26; i++) {
            int x;
            cin >> x;
            cout << char('a' + x - 1);
        }
        return 0;
    }
    

    C - Shapes

    题意

    给出两个 (n imes n) 的图形,判断能否通过旋转(每次九十度)、平移使得二者重合。

    • (1 le n le 200)

    题解

    枚举旋转的次数,若二者可以平移至重合则所有横纵坐标之差相等。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        cin >> n;
        vector<string> MP1(n), MP2(n);
        for (int i = 0; i < n; i++) {
            cin >> MP1[i];
        }
        for (int i = 0; i < n; i++) {
            cin >> MP2[i];
        }
        auto rotate = [](int n, vector<string>& MP) { // n x n 90 degree clockwise
            auto t_MP(MP);
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    t_MP[j][n - 1 - i] = MP[i][j];
                }
            }
            MP = t_MP;
        };
        bool ok = false;
        for (int t = 0; t < 4; t++) {
            rotate(n, MP1);
            vector<int> x1, y1, x2, y2;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (MP1[i][j] == '#') {
                        x1.push_back(i), y1.push_back(j);
                    }
                    if (MP2[i][j] == '#') {
                        x2.push_back(i), y2.push_back(j);
                    }
                }
            }
            if (x1.size() != x2.size()) {
                continue;
            }
            bool trans = true;
            for (int i = 0; i < (int)x1.size(); i++) {
                if (x1[i] - x2[i] != x1[0] - x2[0] or y1[i] - y2[i] != y1[0] - y2[0]) {
                    trans = false;
                }
            }
            if (trans) {
                ok = true;
            }
        }
        cout << (ok ? "Yes" : "No") << "
    ";
        return 0;
    }
    

    D - Rectangles

    题意

    给出平面上 (n) 个不等的点,判断可以形成多少与横纵坐标轴平行的矩形。

    • (4 le n le 2000)

    题解

    枚举对角顶点即可,同一个矩形会被主副对角线枚举两次,所以最终答案还要再除以二。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        cin >> n;
        vector<int> x(n), y(n);
        map<pair<int, int>, bool> mp;
        for (int i = 0; i < n; i++) {
            cin >> x[i] >> y[i];
            mp[{x[i], y[i]}] = true;
        }
        int ans = 0;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if (x[i] == x[j] or y[i] == y[j]) {
                    continue;
                }
                if (mp[{x[i], y[j]}] and mp[{x[j], y[i]}]) {
                    ++ans;
                }
            }
        }
        cout << ans / 2 << "
    ";
        return 0;
    }
    

    E - Destruction

    题意

    给出一个 (n) 个点 (m) 条边的无向连通图,每次可以移除一条边,收益为该边的权值 (c_i)

    问在保证图连通的情况下,最大收益为多少。

    • (2 le n le 2 imes 10^5)

    • (n - 1 le m le 2 imes 10^5)

    • (-10^9 le c_i le 10^9)

    题解

    类似最小生成树的思想,只不过在计算收益时只考虑非负权边。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    struct dsu {
        vector<int> fa, sz;
     
        dsu(int n) : fa(n), sz(n) {
            iota(fa.begin(), fa.end(), 0);
            fill(sz.begin(), sz.end(), 1);
        }
     
        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) {
                return;
            }
            if (sz[x] < sz[y]) {
                swap(x, y);
            }
            sz[x] += sz[y];
            fa[y] = x;
        }
     
        int Size(int x) {
            return fa[x] == x ? sz[x] : sz[x] = sz[Find(x)];
        }
     
        bool Diff(int x, int y) {
            return Find(x) != Find(y);
        }
    };
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n, m;
        cin >> n >> m;
        vector<tuple<int, int, int>> edge(m);
        long long ans = 0;
        for (auto& [w, u, v] : edge) {
            cin >> u >> v >> w;
            --u, --v;
            if (w >= 0) {
                ans += w;
            }
        }
        sort(edge.begin(), edge.end());
        dsu dsu(n);
        for (auto [w, u, v] : edge) {
            if (dsu.Diff(u, v)) {
                dsu.Union(u, v);
                if (w >= 0) {
                    ans -= w;
                }
            }
        }
        cout << ans << "
    ";
        return 0;
    }
    

    F - Blocked Roads

    题意

    给出一个 (n) 个点 (m) 条边的有向图,问如果移除第 (i) 条边,结点 (1) 与结点 (n) 的最短距离为多少。

    • (2 le n le 400)
    • (1 le m le n(n - 1))

    题解

    (Dijkstra)(O_{(n^2)})(O_{((n + m)log_n)}) 两种实现方法,本题中结点数 (n) 较少,所以可以先确定一条从 (1)(n) 的最短路径,之后若第 (i) 条边不在此路径中,直接输出 (dis_{(1, n)}) 即可,否则移除该边后重跑一遍 (O_{(n^2)})(Dijkstra) ,因为路径中最多含有 (n - 1) 条边,所以最坏时间复杂度为 (O_{(n^3)})

    Tips

    移除边后记得回溯。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n, m;
        cin >> n >> m;
        vector<vector<int>> edge(n, vector<int> (n, 1e9));
        vector<int> u(m), v(m);
        for (int i = 0; i < m; i++) {
            cin >> u[i] >> v[i];
            --u[i], --v[i];
            edge[u[i]][v[i]] = 1;
        }
        vector<int> dis(n), pre(n, -1);
        auto Dijkstra = [&]() {
            fill(dis.begin(), dis.end(), 1e9);
            dis[0] = 0;
            queue<int> que;
            que.push(0);
            vector<bool> vis(n);
            vis[0] = true;
            while (not que.empty()) {
                int u = que.front();
                que.pop();
                for (int v = 0; v < n; v++) {
                    if (not vis[v] and dis[u] + edge[u][v] < dis[v]) {
                        dis[v] = dis[u] + edge[u][v];
                        vis[v] = true;
                        pre[v] = u;
                        que.push(v);
                    }
                }
            }
        };
        Dijkstra();
        vector<vector<bool>> used(n, vector<bool> (n));
        for (int u = pre[n - 1], v = n - 1; u != -1; v = u, u = pre[u]) {
            used[u][v] = true;
        }
        for (int i = 0; i < m; i++) {
            if (used[u[i]][v[i]]) {
                edge[u[i]][v[i]] = 1e9;
                Dijkstra();
                cout << (dis[n - 1] == 1e9 ? -1 : dis[n - 1]) << "
    ";
                edge[u[i]][v[i]] = 1;
                Dijkstra();
            } else {
                cout << (dis[n - 1] == 1e9 ? -1 : dis[n - 1]) << "
    ";
            }
        }
        return 0;
    }
    

    G - Game on Tree 2

    题意

    给出一棵有 (n) 个结点的树,每个结点的权值为 (a_i)

    初始时结点 (1) 处有一枚棋子,Alice 先手,Bob 后手,每次可以将棋子从当前结点移至任一未访问过的相邻结点。

    最终收益为所经结点权值 multiset 的中位数,Alice 想要将其最大化,Bob 想要将其最小化,双方均采取最优策略,问最终集合的中位数会是多少。

    中位数的定义 若集合大小为奇数,则为中间的数,否则为中间两个数的平均值。
    • (2 le n le 10^5)
    • (2 le a_i le 10^9)(a_i) 均为偶数

    题解

    假设结点 (1) 为根节点,那么每个叶结点的中位数都是唯一确定的,同时可以由深度确定本轮操作者,利用 (dfs) + 回溯 进行树上 (dp) 即可。

    更新、询问集合的中位数可以用 坐标压缩 + 权值树状数组,也可以用两个 multiset 分别保存前后一半的值。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    struct Kth_multiset {
        multiset<int> mst1, mst2; // always mst2.size() == mst1.size or mst2.size() == mst1.size + 1   for example: mst1:{2, 4} mst2:{4, 6, 8}
    
        void balance() {
            if (mst2.size()) {
                mst1.insert(*mst2.begin());
                mst2.erase(mst2.begin());
            }
            while (mst1.size() > mst2.size()) {
                mst2.insert(*mst1.rbegin());
                mst1.erase(prev(mst1.end()));
            }
        }
    
        void insert(int val) { // all vals should be even
            mst2.insert(val);
            balance();
        }
    
        void erase(int val) {
            if (mst2.find(val) != mst2.end()) {
                mst2.erase(mst2.find(val));
            } else {
                mst1.erase(mst1.find(val));
            }
            balance();
        }
    
        int find_kth() {
            if (mst2.size() == mst1.size() + 1) {
                return *mst2.begin();
            } else {
                return (*mst1.rbegin() + *mst2.begin()) / 2; // because of here
            }
        }
    } K;
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        cin >> n;
        vector<int> a(n);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        vector<vector<int>> G(n);
        for (int i = 0; i < n - 1; i++) {
            int u, v;
            cin >> u >> v;
            --u, --v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        vector<int> dp(n);
        function<void(int, int, int)> dfs = [&](int u, int p, int d) {
            K.insert(a[u]);
            int mi = 2e9, mx = 0;
            for (auto v : G[u]) {
                if (v != p) {
                    dfs(v, u, d + 1);
                    mi = min(mi, dp[v]), mx = max(mx, dp[v]);
                }
            }
            if (mx == 0) { // is leaf
                dp[u] = K.find_kth();
            } else { 
                dp[u] = d & 1 ? mi : mx;
            }
            K.erase(a[u]);
        };
        dfs(0, -1, 0);
        cout << dp[0] << "
    ";
        return 0;
    }
    

    参考

    https://atcoder.jp/contests/abc218/submissions/25764499

    https://atcoder.jp/contests/abc218/editorial/2631

  • 相关阅读:
    相似矩阵
    特征值和特征向量
    非齐次方程组的通解
    线性方程组解的性质和结构、基础解系
    高斯消元法求齐次线性方程的通解
    从零开始学 Web 之 HTML(三)表单
    从零开始学Web之HTML(二)标签、超链接、特殊符号、列表、音乐、滚动、head等
    从零开始学 Web 之 HTML(一)认识前端
    JavaScript基础(一)概述
    如何恢复windows的exe文件的默认打开方式
  • 原文地址:https://www.cnblogs.com/Kanoon/p/15262807.html
Copyright © 2011-2022 走看看