• Codeforces Round #675 (Div. 2)【ABCD】


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

    A. Fence

    题意

    给出三条边 $a,b,c$,构造第四条边使得四者可以围成一个四边形。

    题解

    $d = max(a,b,c)$,可以将四条边中最长的两条边想象成一把可以开合的尺子。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) {
            int a, b, c;
            cin >> a >> b >> c;
            cout << max({a, b, c}) << "
    ";
        }
        return 0;
    }

    B. Nice Matrix

    题意

    定义各行列数值均对称的矩阵为好矩阵,给出一个 $n imes m$ 的矩阵,每次操作可以给一个数加一或减一,计算将它转为好矩阵的最少操作次数。 

    题解

    因为矩阵有两条中轴线,所以一个数最多需要与三个数对称相等,至于等的值,考虑 $1, 2, 6, 10$ :

    对于 $1,10$,只要等的值位于 $[1,10]$ 内,将二者变为相等的操作次数是相同的;

    同理,对于 $2,6$,只要等的值位于 $[2,6]$ 内,将二者变为相等的操作次数也是相同的。

    所以,最终等的值选取所有数排序后的中间区间内的任一值均可。

    代码

    #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, m;
            cin >> n >> m;
            vector<vector<int>> a(n, vector<int> (m));
            for (auto &v : a)
                for (auto &x : v) cin >> x;
            long long ans = 0;
            vector<vector<bool>> vis(n, vector<bool> (m));
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    vector<int> v;
                    for (int x : {i, n - 1 - i}) {
                        for (int y : {j, m - 1 - j}) {
                            if (!vis[x][y]) {
                                v.push_back(a[x][y]);
                                vis[x][y] = true;
                            }
                        }
                    }
                    if (v.size() >= 2) {
                        sort(v.begin(), v.end());
                        for (auto i : v) ans += abs(i - v[1]);
                    }
                }
            }
            cout << ans << "
    ";
        }
        return 0;
    }

    C. Bargain

    题意

    给出一个数并抹去它的一段连续区间后将余下的数连接,计算所有可能得到的数之和。

    题解

    个位前的 $n-1$ 个数位有 $frac{n(n-1)}{2}$ 个连续区间,所以个位可以作为个位加 $frac{n(n-1)}{2}$ 次,个位之前的每个数位因为要抹去后面所有的数位,所以作为个位只可以加 $1$ 次;

    同理:

    十位可以作为十位加 $frac{(n-1)(n-2)}{2}$ 次,十位之前的每个数位可以作为十位加 $2$ 次;

    千位可以作为千位加 $frac{(n-2)(n-3)}{2}$ 次,千位之前的每个数位可以作为千位加 $3$ 次;

    …………

    即每次将当前数位与之前数位的总和分别计算。

    对于每次之前数位的总和可以维护一个前缀和。

    代码

    #include <bits/stdc++.h>
    using ll = long long;
    using namespace std;
    constexpr int MOD = 1e9 + 7;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        string s;
        cin >> s;
        ll sum = 0;
        for (char c : s) sum += c - '0';
        ll ans = 0,  p = 1;
        for (ll i = s.size() - 1; i >= 0; i--) {
            ll val = (s[i] - '0');
            ll mul = i * (i + 1) / 2;
            ll pre_val = (sum -= s[i] - '0');
            ll pre_mul = s.size() - i;
            ans += (val * mul + pre_val * pre_mul) % MOD * p % MOD;
            ans %= MOD;
            p = (p * 10) % MOD;
        } 
        cout << ans << "
    ";
        return 0;
    }

    D. Returning Home

    题意

    有一个 $n imes n$ 的方阵,每次可以花 $1$ 秒走到相邻的方格,方阵中有一些传送点,传送到所在行或列的传送点不花费时间,计算从 $(sx,sy)$ 走到 $(fx,fy)$ 的最短时间。

    题解

    共可分为两种情况:

    • 不经传送点直接从起点走到终点
    • 经过一个或多个传送到走到终点

    第一种情况:所花时间即 $abs(sx-fx)+abs(sy-fy)$ 。

    第二种情况:以相同的端点分别对传送点的横、纵坐标从小到大两两相邻建边,然后计算从起点到每个传送点的最短距离,最后枚举最终转折点,答案即 $min(dis_i + abs(fx - x_i) + abs(fy - y_i))$ 。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n, m;
        cin >> n >> m;
        int sx, sy, fx, fy;
        cin >> sx >> sy >> fx >> fy;
        vector<int> x(m), y(m); 
        for (int i = 0; i < m; i++) {
            cin >> x[i] >> y[i];
        }
        vector<vector<pair<int, int>>> G(m);
        vector<int> p(m);
        iota(p.begin(), p.end(), 0);
        //横坐标从小到大相邻建边
        sort(p.begin(), p.end(), [&](int i, int j) {
            return x[i] < x[j];
        });
        for (int i = 0; i + 1 < m; i++) {
            int u = p[i];
            int v = p[i + 1];
            int w = x[p[i + 1]] - x[p[i]];
            G[u].emplace_back(v, w);
            G[v].emplace_back(u, w);
        }
        //纵坐标从小到大相邻建边
        sort(p.begin(), p.end(), [&](int i, int j) {
            return y[i] < y[j];
        });
        for (int i = 0; i + 1 < m; i++) {
            int u = p[i];
            int v = p[i + 1];
            int w = y[p[i + 1]] - y[p[i]];
            G[u].emplace_back(v, w);
            G[v].emplace_back(u, w);
        }
        //初始答案为不经过传送点直接走到终点
        long long ans = abs(sx - fx) + abs(sy - fy);
        priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pque;
        vector<long long> dis(m);
        vector<bool> vis(m);
        //计算起点到每个传送点的初始距离
        for (int i = 0; i < m; i++) {
            pque.emplace(min(abs(sx - x[i]), abs(sy - y[i])), i);
        }
        //计算起点到每个传送点的最短距离
        while (!pque.empty()) {
            auto [d, u] = pque.top();
            pque.pop();
            if (vis[u]) continue;
            vis[u] = true;
            dis[u] = d;
            for (auto [v, w] : G[u]) {
                pque.emplace(d + w, v);
            }
        }
        //枚举以哪个传送点为最后转折点走到终点
        for (int i = 0; i < m; i++) {
            ans = min(ans, dis[i] + abs(fx - x[i]) + abs(fy - y[i]));
        }
        cout << ans << "
    ";
        return 0;
    }
  • 相关阅读:
    在一个类中写完多线程(sleep 方法和wait 方法的区别)
    final
    Oracle 远程访问配置
    在 Windows Forms 和 WPF 应用中使用 FontAwesome 图标
    C#反序列化XML异常:在 XML文档(0, 0)中有一个错误“缺少根元素”
    C#[Win32&WinCE&WM]应用程序只能运行一个实例:MutexHelper
    『.NET Core CLI工具文档』(十四)dotnet-install 脚本参考
    『.NET Core CLI工具文档』(十三)dotnet-publish
    『.NET Core CLI工具文档』(十二)dotnet-pack
    『.NET Core CLI工具文档』(十一)dotnet-test
  • 原文地址:https://www.cnblogs.com/Kanoon/p/13772088.html
Copyright © 2020-2023  润新知