zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 222 复盘

    A. Four Digits

    一遍 AC。

    int n;
    
    int main() {
        scanf("%d", &n);
        std::string str = std::to_string(n);
        while (str.size() != 4) str = '0' + str;
        printf("%s
    ", str.c_str());
        return 0;
    }
    

    B. Failing Grade

    一遍 AC。

    int n, p;
    
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n >> p;
        int ans = 0;
        rep (i, 1, n) {
            int x; cin >> x;
            ans += (x < p);
        }
        cout << ans << endl;
        return 0;
    }
    

    C. Swiss-System Tournament

    机房里吵得读不下去题,拖到后面才做的。

    WA 了 1 发,先是读错题,然后又打了好几个 typo。

    #错误警示:拒绝打错微小字符,比如 ij
    #错误警示:读好题目的数据范围信息,比如 (2n) 个人需要开两倍数组。

    const int MAXN = 50 + 10;
    const int MAXM = 100 + 10;
    
    int judge(int id1, char s1, int id2, char s2) {
        if (s1 == s2) return 2;
        if (s1 == 'G') return s2 == 'C';
        if (s1 == 'C') return s2 == 'P';
        /* s1 == 'P' */ return s2 == 'G';
    }
    
    int n, m;
    char give[MAXN * 2][MAXM];
    int rank[MAXN * 2]; // do not forget
    struct ND { int val, id; } wins[MAXN * 2];
    
    bool cmp(ND x, ND y) { return x.val == y.val ? x.id < y.id : x.val > y.val; }
    bool cmp2(ND x, ND y) { return x.id < y.id; }
    
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n >> m;
        rep (i, 1, 2 * n) { cin >> (give[i] + 1); rank[i] = i; wins[i].id = i; }
        rep (i, 1, m) {
            // typo: i -> j
            std::sort(wins + 1, wins + 1 + 2 * n, cmp2);
            rep (j, 1, n) {
                int s1 = rank[j * 2 - 1], s2 = rank[j * 2];
                if (judge(s1, give[s1][i], s2, give[s2][i]) == 2) continue;
                if (judge(s1, give[s1][i], s2, give[s2][i])) ++wins[s1].val;
                else ++wins[s2].val;
            } std::sort(wins + 1, wins + 1 + 2 * n, cmp);
            rep (j, 1, 2 * n) rank[j] = wins[j].id;
            // rep (x, 1, 2 * n) cout << rank[x] << ' ';
            // cout << endl;
        }
        rep (i, 1, 2 * n) cout << rank[i] << endl;
        return 0;
    }
    

    D. Between Two Arrays

    f[i][j] 表示考虑前 i 个限制,第 i 次选的数是 j 的方案数。搞一个前缀和优化转移即可。

    一遍 AC。

    const int MAXN = 3000 + 10;
    const int MAXS = 3000;
    const int HA = 998244353;
    
    int n, aa[MAXN], bb[MAXN];
    int dp[MAXN][MAXN];
    lli sumdp[MAXN][MAXN]; // sum of dp[i][1~j]
    
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n;
        rep (i, 1, n) cin >> aa[i];
        rep (i, 1, n) cin >> bb[i];
        rep (i, 1, 1) {
            rep (x, aa[i], bb[i]) dp[i][x] = 1;
            rep (x, aa[i], MAXS) (sumdp[i][x] = sumdp[i][x - 1] + dp[i][x]) %= HA;
        }
        rep (i, 2, n) {
            rep (j, aa[i], bb[i]) {
                dp[i][j] = sumdp[i - 1][j];
            } rep (j, aa[i], MAXS) (sumdp[i][j] = sumdp[i][j - 1] + dp[i][j]) %= HA;
        }
        cout << sumdp[n][bb[n]] << endl;
        return 0;
    }
    

    E. Red and Blue Tree

    首先可以算出每条边被经过的次数 (c_i),然后就可以 DP 了。

    最开始想的是 f[i][j] 表示前 (i) 条边,(R - B = j) 的方案数,但是时空复杂度是 (O(N|K|)) 的,可不可以滚动数组没试过,总觉得应该过不去就没写。

    题解又做了一步转化:设 (S = sum c_i),于是题目转化成了选择一些 (c_i) 求和得到 (frac{S + K}{2}) 的方案数((S + K < 0) 或是偶数的情况即是无解)。这就是一个背包板子了。

    时间复杂度还是 (O(N|K|)) 居然能过 离谱。

    const int MAXN = 1000 + 10;
    const int MAXM = 100000 + 10;
    const int HA = 998244353;
    
    int n, m, k;
    struct E { int v, id; };
    std::vector<E> G[MAXN];
    
    int cnt[MAXN];
    int dp[MAXM];
    
    bool dfs(int u, int fa, int end) {
        if (u == end) return true;
        bool ans = false;
        forall (G[u], i) {
            int v = G[u][i].v, id = G[u][i].id;
            if (v == fa) continue;
            if (dfs(v, u, end)) {++cnt[id]; ans = true;}
        } return ans;
    }
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n >> m >> k;
        std::vector<int> vc;
        rep (i, 1, m) { int x; cin >> x; vc.push_back(x); }
        rep (i, 1, n - 1) {
            int u, v; cin >> u >> v;
            G[u].push_back({v, i}); G[v].push_back({u, i});
        }
        rep (i, 1, m - 1) {
            dfs(vc[i - 1], 0, vc[i]);
        }
        int S = 0;
        rep (i, 1, n - 1) {
            S += cnt[i];
        }
        if ((S + k) < 0 || ((S + k) & 1)) {
            cout << 0 << endl; return 0;
        }
        dp[0] = 1;
        for (int i = 1; i <= n - 1; ++i) {
            for (int j = MAXM - 10; j >= cnt[i]; --j) {
                (dp[j] += dp[j - cnt[i]]) %= HA;
            }
        } cout << dp[(S + k) >> 1] << endl;
        return 0;
    }
    

    F. Expensive Expense

    树的直径端点。

    后悔考场上没开这题。

    交了好几发没过,一查发现是 disdist 写 typo 了。

    #错误警示:写代码专注一点,不要纯靠肌肉记忆,因为你肌肉记忆的和这题可能有些出入。

    const int MAXN = 200000 + 10;
    int n;
    lli val[MAXN];
    
    struct E { int v; lli val; }; std::vector<E> G[MAXN];
    bool operator < (const E &x, const E &y) {
        return x.val > y.val;
    }
    
    lli dist[MAXN];
    void sp(int st, lli *dis) {
        for (int i = 1; i <= n; ++i) dis[i] = (1ll << 62); 
        std::priority_queue<E> q;
        static bool vis[MAXN]; memset(vis, 0, sizeof vis);
        q.push({st, dis[st] = 0});
        while (!q.empty()) {
            int u = q.top().v; q.pop();
            if (vis[u]) continue;
            vis[u] = true;
            forall (G[u], i) {
                int v = G[u][i].v, w = G[u][i].val;
                // typo: dist dis
                if (dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    q.push({v, dis[v]});
                }
            }
        }
    }
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n;
        rep (i, 1, n - 1) {
            int u, v, w; cin >> u >> v >> w;
            G[u].push_back({v, w}); G[v].push_back({u, w});
        }
        rep (i, 1, n) cin >> val[i];
    
        int s1 = 0;
        sp(1, dist);
        for (int i = 1; i <= n; ++i) {
            if (dist[s1] + val[s1] < dist[i] + val[i]) {
                s1 = i;
            }
        }
        sp(s1, dist);
        int s2 = 0;
        for (int i = 1; i <= n; ++i) {
            if (s1 == i) continue;
            if (dist[s2] + val[s2] < dist[i] + val[i]) {
                s2 = i;
            }
        }
        // DEBUG(s1); DEBUG(s2);
        static lli dist2[MAXN];
        sp(s2, dist2);
        for (int i = 1; i <= n; ++i) {
            // DEBUG(dist[i]); DEBUG(dist2[i]);
            if (i == s1) cout << dist[s2] + val[s2] << endl;
            else if (i == s2) cout << dist2[s1] + val[s1] << endl;
            else {
                if (dist2[i] + val[s2] > dist[i] + val[s1]) cout << dist2[i] + val[s2] << endl;
                else cout << dist[i] + val[s1] << endl;
            }
        }
        return 0;
    }
    
  • 相关阅读:
    C# 学习历程——接口
    C# 学习历程——类的封装,继承与多态
    C# 学习历程——C#基础
    C# 学习历程——Hello World
    python(14)---发邮件、写日志、操作redis数据库
    python(13)——内置函数
    python(12)---导入模块
    HTML操作之DOM操作
    HTML基础之CSS
    HTML基础之HTML标签
  • 原文地址:https://www.cnblogs.com/handwer/p/15402876.html
Copyright © 2011-2022 走看看