AtCoder ABC 218

A - Weather Forecast

解题思路

签到。

Code

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    
    int n;
    string s;
    cin >> n >> s;
    cout << (s[n - 1] == 'o' ? "Yes" : "No") << '\n';
 
    return 0;
}

B - qwerty

解题思路

签到。

Code

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    
    for (int i = 1; i <= 26; i++) {
        int x;
        cin >> x;
        cout << (char)(x + 'a' - 1);
    }
    cout << '\n';
 
    return 0;
}

C - Shapes

解题思路

模拟,顺时针旋转 \(4\) 次,然后分别判断,只要比较 # 的点能否通过平移重合(这里可以利用坐标差判断)。

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;


int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    string s[n], t[n];
    for (int i = 0; i < n; i++) {
        cin >> s[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> t[i];
    }
    auto check = [&]() {
        vector<array<int, 2>> a, b;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (s[i][j] == '#') a.push_back({i, j});
                if (t[i][j] == '#') b.push_back({i, j});
            }
        }
        if (a.size() != b.size()) return false;
        for (int i = 0; i < a.size(); i++) {
            if (a[i][0] - b[i][0] != a[0][0] - b[0][0] || a[i][1] - b[i][1] != a[0][1] - b[0][1]) {
                return false;
            }
        }
        return true;
    };

    auto rotate = [&]() {
        string c[n];
        for (int i = 0; i < n; i++) c[i].resize(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                c[j][n - i - 1] = t[i][j];
            }
        }
        for (int i = 0; i < n; i++) t[i] = c[i];
    };

    int times = 4;
    while (times--) {
        if (check()) {
            cout << "Yes\n";
            return 0;
        }
        rotate();
    }
    cout << "No\n";

    return 0;
}

D - Rectangles

题意

给你 \(n\) 个点,问你可以选出几种方案使得其中 \(4\) 个点可以构成一个平行于 \(x\) 轴或者 \(y\) 轴的矩形?

数据范围

\(1\leq n \leq 2000\)\(0\leq x_i,y_i \leq 10^9\)

解题思路

我们考虑枚举矩形的其中两个不在同一水平线或者竖直线上的点 \((x_1,y_1),(x_2,y_2)\),那么我们不难推出剩下两个点要为:\((x_1,y_2),(x_2,y_1)\)
\(set\) 维护这样的点即可,注意最后要 \(/2\),因为同一个矩形会被统计 \(2\) 次。

Code

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    
    int n;
    cin >> n;
    vector<array<int, 2>> point(n + 1);
    set<array<int, 2>> se;
    for (int i = 1; i <= n; i++) {
        auto &[x, y] = point[i];
        cin >> x >> y;
        se.insert({x, y});
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            auto [x1, y1] = point[i];
            auto [x2, y2] = point[j];
            if (x1 != x2 && y1 != y2) {
                if (se.count({x1, y2}) && se.count({x2, y1})) ans++;
            }
        }
    }
    cout << ans / 2 << '\n';

    return 0;
}

E - Destruction

题意

给你一个 \(n\) 个点 \(m\) 条边的无向连通图,你可以删去图中任意的多条边,只要保证删除之后,图任然是连通的,若边 \(u-v\) 边权为 \(w\),若 \(w\geq 0\),则你可以获得 \(w\),否则你将亏损 \(|w|\)
现在问你,最大能获得的价值是多少?

数据范围

  • \(2\leq n \leq 2\times 10^5\)
  • \(n-1\leq m \leq 2\times 10^5\)
  • \(1\leq a_i,b_i \leq n\)
  • \(-10^9\leq w_i \leq 10^9\)

解题思路

我们不难想到要让图连通至少需要 \(n-1\) 条边,我们不难想到生成树,我们肯定是能删就删,故我们最后必然会保留一棵树的形态,那么问题等价于我们只要让这棵生成树的 \(w\) 都尽可能小
那么最后我们能删的 \(w\) 就是尽可能大的,故我们效仿最小生成树的做法,按边权从小到大排序,然后用并查集维护即可,只要出现一条边所连的两个连通块已经在一块,若此时 \(w\geq 0\) ,则我们可以获得这样的价值,\(w<0\) 的边我们可以不用管。

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
array<int, 3> e[N];
int p[N];
int find(int x) {
    return x == p[x] ? x : p[x] = find(p[x]);
}
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        e[i] = {w, u, v};
    }
    sort(e + 1, e + 1 + m);
    for (int i = 1; i <= n; i++) {
        p[i] = i;
    }
    LL ans = 0;
    for (int i = 1; i <= m; i++) {
        auto [w, u, v] = e[i];
        u = find(u), v = find(v);
        if (u == v && w > 0) ans += w;
        else p[u] = v; 
    }
    cout << ans << '\n';

    return 0;
}

F - Blocked Roads

题意

给你 \(n\) 个点 \(m\) 条边的有向图,现在需要你计算每次删掉第 \(i\) 条边之后,从 \(1\) 走到 \(n\) 的最短距离,如果不存在输出 \(-1\)

数据范围

\(1\leq n \leq 400\)\(1\leq m \leq n(n - 1)\)\(1\leq s_i,t_i \leq n\)

解题思路

首先引出最短路径树,对于任何最短路算法,我们都可以构建一棵最短路径树,使得根节点是起点,它到树上任意节点形成的路径就是原图中一条从起点到某点的最短路径
注意最短路径树并不是唯一的。

我们不难发现,如果删除的边不在最短路径树上,那么删完之后,不会影响任何点的最短路;若删除的是树边,我们则要重新计算。
故我们发现我们只要枚举那些树边即可,这样的树边只有 \(n-1\) 条,所以我们就得到了一个时间复杂度为 \(O(n(n+m))\) 的算法。
我们只要先用 \(BFS\) 在求最短路途中,建立好最短路径树,或者说记录一下任意一条从 \(1->n\) 的最短路径是哪个,任何我们只要枚举删去最短路径上的边,然后再去更新最短路即可。

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;


int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> G(n + 1, vector<int>(n + 1, -1));
    vector<array<int, 2>> e(m + 1);
    for (int i = 1; i <= m; i++) {
        int a, b;
        cin >> a >> b;
        G[a][b] = i;
        e[i] = {a, b};
    }
    queue<int> q;
    vector<int> dis(n + 1, -1);
    vector<array<int, 2>> pre(n + 1, {-1, -1});
    dis[1] = 0;
    q.push(1);
    while (q.size()) {
        int u = q.front();
        q.pop();
        for (int i = 1; i <= n; i++) {
            if (G[u][i] != -1 && dis[i] == -1) {
                dis[i] = dis[u] + 1;
                q.push(i);
                pre[i] = {u, G[u][i]};
            }
        }
    }
    vector<int> ans(m + 1, dis[n]);
    vector<int> path;
    int cur = n;
    while (cur != 1 && pre[cur][1] != -1) {
        path.push_back(pre[cur][1]);
        cur = pre[cur][0];
    }
    for (auto id : path) {
        G[e[id][0]][e[id][1]] = -1;
        queue<int> q;
        vector<int> dis(n + 1, -1);
        dis[1] = 0;
        q.push(1);
        while (q.size()) {
            int u = q.front();
            q.pop();
            for (int v = 1; v <= n; v++) {
                if (G[u][v] != -1 && dis[v] == -1) {
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
        ans[id] = dis[n];
        G[e[id][0]][e[id][1]] = id;
    }
    for (int i = 1; i <= m; i++) {
        cout << ans[i] << "\n";
    }

    return 0;
}
posted @ 2023-08-09 12:35  jackle  阅读(37)  评论(0)    收藏  举报