• Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises)


    传送门

    A. Optimal Currency Exchange

    枚举一下就行了。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n, a, b;
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n >> a >> b; b *= 5;
        int ans = n;
        for(int x = 1; x * b <= n; ++x) {
            ans = min(ans, (n - x * b) % a);
        }
        for(int x = 1; x * a <= n; ++x) {
            ans = min(ans, (n - x * a) % b);
        }
        cout << ans;
        return 0;
    }
    

    B. Badges

    同样也是枚举,注意边界情况。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int b, g, n;
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> b >> g >> n;
        int mn = min(b, g);
        int mx = max(g, b);
        int ans = 0;
        for(int i = mn; ~i; i--) {
            int j = n - i;
            if(j <= mx && j >= 0) ans++  ;
        }
        cout << ans;
        return 0;
    }
    

    C. Bad Sequence

    水题,有很多做法,最简单的做法就是维护一个类似前缀和的形式,题目的条件就相当于在任何一个位置,')'的数量不会比'('的数量多1。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 200005;
    int n;
    char s[N];
    char q[N];
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
    //    freopen("input.in", "r", stdin);
        cin >> n >> s + 1;
        int l = 1, r = 0;
        for(int i = 1; i <= n; i++) {
            if(l > r) q[++r] = s[i];
            else {
                if(s[i] == ')' && q[r] == '(') {
                    --r;
                } else q[++r] = s[i];
            }
        }
        int len = r - l + 1;
        int f = 1;
        if(len == 2) {
            if(q[l] == ')' && q[r] == '(') {}
            else f = 0;
        } else if(len == 0) {}
        else f = 0;
        if(f) cout << "YES";
        else cout << "NO";
        return 0;
    }
    

    D. Treasure Island

    题意:
    给出一个(n*m)的网格图,现在要堵住一些点,使得从((1,1))出发,每次只能向右走或者向下走,到不了((n,m))
    问最少需要堵住多少点。

    思路:
    很显然答案不会大于(2)。那么我们就只需要判断答案是否可能为(0,1)就行。

    • 考虑直接bfs,从起点出发一次,从终点出发一次。
    • 合理性?
    • 首先(0)的情况很好判断,我们就只需要判断答案是否有可能为(1)
    • 假设网格图中存在一个点为必经点,那么可以观察到该点的左下部分和右上部分从两端点出发都不能同时到达。

    然而我比赛时写得代码很丑陋= =其实点直接映射就好,写起来很方便;同时(bfs)也可以直接用循环代替。

    Code
    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    #define MP make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 1e6 + 5;
    int n, m;
    char s[N];
    int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
    bool ok(int x, int y) {
        return x >= 1 && x <= n && y >= 1 && y <= m;
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n >> m;
        vector <vector <int> > a(n + 3), b(n + 3), c(n + 3), sum(n + 3);
        vector <vector <vector <int> >> d(2);
        for(int i = 0; i < 2; i++) {
            d[i].resize(n + 3);
        }
        for(int i = 0; i <= n + 1; i++) {
            d[0][i].resize(m + 3, INF);
            d[1][i].resize(m + 3, INF);
        }
        for(int i = 0; i <= n + 1; i++)
            a[i].resize(m + 3), b[i].resize(m + 3, 0), c[i].resize(m + 3, 0), sum[i].resize(m + 3, 0);
        for(int i = 1; i <= n; i++) {
            cin >> s + 1;
            for(int j = 1; j <= m; j++) {
                if(s[j] == '.') a[i][j] = 0;
                else a[i][j] = 1;
            }
        }
        vector <vector<int> > vis;
        vis.resize(n + 2);
        for(int i = 1; i <= n; i++) vis[i].resize(m + 2, 0);
        queue <pii> q;
        q.push(MP(1, 1));
        vis[1][1] = 1; d[0][1][1] = 0;
        while(!q.empty()) {
            pii cur = q.front(); q.pop();
            for(int i = 0; i < 2; i++) {
                int curx = cur.fi + dx[i], cury = cur.se + dy[i];
                if(ok(curx, cury) && !vis[curx][cury] && a[curx][cury] == 0) {
                    vis[curx][cury] = 1;
                    d[0][curx][cury] = d[0][cur.fi][cur.se] + 1;
                    q.push(MP(curx, cury));
                }
            }
        }
        if(d[0][n][m] == INF) {
            cout << 0; return 0;
        }
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) vis[i][j] = 0;
        }
        q.push(MP(n, m));
        vis[n][m] = 1; d[1][n][m] = 0;
        while(!q.empty()) {
            pii cur = q.front(); q.pop();
            for(int i = 2; i < 4; i++) {
                int curx = cur.fi + dx[i], cury = cur.se + dy[i];
                if(ok(curx, cury) && !vis[curx][cury] && a[curx][cury] == 0) {
                    vis[curx][cury] = 1;
                    d[1][curx][cury] = d[1][cur.fi][cur.se] + 1;
                    q.push(MP(curx, cury));
                }
            }
        }
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if(a[i][j]) continue;
                sum[i][j] = d[0][i][j] + d[1][i][j];
                if(sum[i][j] >= INF) sum[i][j] = 0;
            }
        }
        for(int i = n; i; i--) {
            for(int j = 1; j <= m; j++) {
                b[i][j] = b[i + 1][j] + b[i][j - 1] - b[i + 1][j - 1] + sum[i][j];
            }
        }
        for(int i = 1; i <= n; i++) {
            for(int j = m; j; j--) {
                c[i][j] = c[i - 1][j] + c[i][j + 1] - c[i - 1][j + 1] + sum[i][j];
            }
        }
        int ans = 2;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if((i == 1 && j == 1) || (i == n && j == m)) continue;
    //            if(a[i][j] == 0 && b[min(i + 1, n)][max(j - 1, 1)] == 0 && c[max(i - 1, 1)][min(j + 1, m)] == 0) {
    //                ans = 1;
    //            }
                if(a[i][j] == 0 && b[i + 1][j - 1] == 0 && c[i - 1][j + 1] == 0) ans = 1;
            }
        }
        cout << ans;
        return 0;
    }
    

    E. Petya and Construction Set

    题意:
    构造一颗(2n)个结点的树,满足(2i,2i-1)两个结点的距离为(d_i,d_ileq n)(d_i)会给出。

    思路:
    (结点看成(n)个,想了一个假题)

    • 注意到一个点只与与它配对的点有关。
    • 考虑将这颗树构造成一条链+一些分支的形式。
    • 首先我们构造一条长度为(n)的链,链上的结点为奇数结点,接下来我们要放偶数结点;
    • 注意到任何长度的点,我们都可以搞一个分支出来。
    • 但是,万一长度大于链的长度怎么办?
    • 那直接将链长度加(1)即可,同时,我们可以按(d_i)降序的顺序来加边,这样可以方便很多。

    细节见代码吧:

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5 + 5;
    int n;
    int d[N];
    vector <int> g[N];
    struct edge{
        int u, v, w;
        bool operator < (const edge &A) const {
            return w > A.w;
        }
    }a[N];
    int p[N];
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n;
        for(int i = 1; i <= n; i++) {
            int u = 2 * i - 1, v = 2 * i;
            cin >> d[i];
            a[i] = {u, v, d[i]};
        }
        sort(a + 1, a + n + 1);
        int MAX = n;
        auto add = [&](int u, int v) {
            g[u].push_back(v);
        };
        for(int i = 1; i <= n; i++) p[i] = a[i].u;
    //    for(int i = 1; i <= n; i++) cout << p[i] << ' ';
    //    cout << '
    ';
        for(int i = 1; i <= n; i++) {
            if(i + a[i].w == MAX + 1) p[++MAX] = a[i].v;
            add(p[i + a[i].w - 1], a[i].v);
            if(i > 1) add(p[i - 1], p[i]);
        }
        for(int i = 1; i <= 2 * n; i++) {
            for(auto it : g[i]) cout << i << ' ' << it << '
    ';
        }
        return 0;
    }
    
  • 相关阅读:
    委托与事件参数的简单运用
    C#消息队列专题
    项目计划流程简易描述
    cookies 客户端历史记录篇
    朋友做的VS2005插件:等号两边值互换
    SSE2指令集系列之二
    SSSE3指令集
    SSE3指令集系列
    SSE特殊指令集系列之一
    SSE2指令集系列之一
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11466474.html
Copyright © 2020-2023  润新知