AISing Programming Contest 2021(AtCoder Beginner Contest 202)

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

A - Three Dice

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

B - 180°

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    string s;
    cin >> s;
    reverse(s.begin(), s.end());
    for (auto& ch : s) {
        if (ch == '6') {
            ch = '9';
        } else if (ch == '9') {
            ch = '6';
        }
    }
    cout << s << "\n";
    return 0;
}

C - Made Up

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    vector<int> a(n), b(n), c(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> b[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> c[i];
        --c[i];
    }
    map<int, int> mp;
    for (int i = 0; i < n; i++) {
        ++mp[b[c[i]]];
    }
    long long ans = 0;
    for (int i = 0; i < n; i++) {
        ans += mp[a[i]];
    }
    cout << ans << "\n";
    return 0;
}

D - aab aba baa

题意

给出 \(a, b\) 的个数, 找出字典序第 \(k\) 小的字符串。

题解

首先需要计算 \(i\)\(a\)\(j\)\(b\) 可以组成多少不同的字符串,这个问题等价于从 \((0,0)\) 走到 \((i,j)\) 有多少种不同的走法,即 \(C_{i + j}^i\) ,由于会溢出 long long ,所以亦可以用动态规划解决,即 \(dp_{ij} = dp_{i - 1j} + dp_{ij - 1}\)

然后逐位推导即可,因为是字典序第 \(k\) 小的字符串,所以先考虑当前位是否可以为 \(a\) 。如果当前位为 \(a\) ,那么剩下不同字符串的个数 \(dp_{i-1j}\) 应该大于等于 \(k\) ,否则当前位为 \(b\) ,同时减去当前位为 \(a\)\(dp_{i - 1 j}\) 种字典序较小的情况。

代码

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int a, b;
    long long k;
    cin >> a >> b >> k;
    vector<vector<long long>> dp(a + 1, vector<long long> (b + 1));
    dp[0][0] = 1;
    for (int i = 0; i <= a; i++) {
        for (int j = 0; j <= b; j++) {
            if (i - 1 >= 0) {
                dp[i][j] += dp[i - 1][j];
            }
            if (j - 1 >= 0) {
                dp[i][j] += dp[i][j - 1];
            }
        }
    }
    function<string(int, int, long long)> find_kth = [&](int a, int b, long long k) {
        if (a == 0) {
            return string(b, 'b');
        }
        if (b == 0) {
            return string(a, 'a');
        }
        if (k <= dp[a - 1][b]) {
            return string("a") + find_kth(a - 1, b, k);
        } else {
            return string("b") + find_kth(a, b - 1, k - dp[a - 1][b]);
        }
    };
    cout << find_kth(a, b, k) << "\n";
    return 0;
}

E - Count Descendants

题意

给出一个有 \(n\) 个结点的树,有 \(q\) 次询问,每次询问中给出整数 \(u,d\) ,问结点 \(u\) 在多少条距离根节点为 \(d\) 的结点的最短路中。

题解

从根节点出发,给每个结点打上一个访问和离开的时间戳,如下图:

example

如果结点 \(v\) 在以结点 \(u\) 为根节点的子树上(即结点 \(v\) 到根节点 \(1\) 的最短路经过结点 \(u\) ),那么显然有 \(in_u \le in_v < out_u\) ,所以记录不同深度中每个结点的访问时间 \(in_i\) ,每次询问从深度为 \(d\) 的所有 \(in_i\) 中二分查找 \(in_u \le in_i < out_u\) 的结点个数即可。

代码

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    vector<vector<int>> G(n);
    for (int v = 1; v < n; v++) {
        int u;
        cin >> u;
        --u;
        G[u].push_back(v);
    }
    int timeStamp = 0;
    vector<int> in(n), out(n);
    vector<vector<int>> list(n);
    function<void(int, int)> dfs = [&](int u, int dep) {
        in[u] = timeStamp++;
        list[dep].push_back(in[u]);
        for (auto v : G[u]) {
            dfs(v, dep + 1);
        }
        out[u] = timeStamp++;
    };
    dfs(0, 0);
    int q;
    cin >> q;
    for (int i = 0; i < q; i++) {
        int u, d;
        cin >> u >> d;
        --u;
        cout << lower_bound(list[d].begin(), list[d].end(), out[u]) - lower_bound(list[d].begin(), list[d].end(), in[u]) << "\n";
    }
    return 0;
}

参考资料

https://atcoder.jp/contests/abc202/editorial

posted @ 2021-05-25 17:20  Kanoon  阅读(110)  评论(0编辑  收藏  举报