zoukankan      html  css  js  c++  java
  • Codeforces Round #722 (Div. 2)

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

    A. Eshag Loves Big Arrays

    题解

    反复选取最小值和大于它的数即可。

    代码

    #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;
            cin >> n;
            vector<int> a(n);
            for (int i = 0; i < n; i++) {
                cin >> a[i];
            }
            cout << n - count(a.begin(), a.end(), *min_element(a.begin(), a.end())) << "
    ";
        }
        return 0;
    }
    

    B. Sifid and Strange Subsequences

    题解

    因为要求任意两对都大于等于最大值,所以排序找相邻最小值,然后枚举当前值能否为最大值即可。

    代码

    #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;
            cin >> n;
            vector<int> a(n);
            for (int i = 0; i < n; i++) {
                cin >> a[i];
            }
            sort(a.begin(), a.end());
            int mi = INT_MAX, ans = 0;
            for (int i = 0; i < n; i++) {
                if (i > 0) {
                    mi = min(mi, a[i] - a[i - 1]);
                }
                if (mi >= a[i]) {
                    ans = i + 1;
                }
            }
            cout << ans << "
    ";
        }
        return 0;
    }
    

    C. Parsa's Humongous Tree

    题解

    每个结点取 (l_i)(r_i) 收益最大,树形 (dp)

    证明

    假设一个结点取 ((l_i, r_i)) 间的某值,设与它相邻的结点中小于此值的有 (p) 个,大于此值的有 (q) 个,根据 (p, q) 的大小关系可以分为以下三种情况:

    • (p < q) ,此时取值向 (l_i) 靠近收益一定增加
    • (p > q) ,此时取值向 (r_i) 靠近收益一定增加
    • (p = q) ,此时取值向 (l_i)(r_i) 靠近收益一定不会减少

    所以,每个结点只取 (l_i)(r_i) 即可。

    代码

    #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;
            cin >> n;
            vector<int> l(n), r(n);
            for (int i = 0; i < n; i++) {
                cin >> l[i] >> r[i];
            }
            vector<vector<int>> G(n);
            for (int i = 0; i < n - 1; i++) {
                int u, v;
                cin >> u >> v;
                --u, --v;
                G[u].push_back(v);
                G[v].push_back(u);
            }
            vector<vector<long long>> dp(n, vector<long long> (2));
            function<void(int, int)> dfs = [&](int u, int p) {
                for (auto v : G[u]) {
                    if (v == p) {
                        continue;
                    }
                    dfs(v, u);
                    dp[u][0] += max(dp[v][0] + abs(l[u] - l[v]), dp[v][1] + abs(l[u] - r[v]));
                    dp[u][1] += max(dp[v][0] + abs(r[u] - l[v]), dp[v][1] + abs(r[u] - r[v]));
                }
            };
            dfs(0, -1);
            cout << max(dp[0][0], dp[0][1]) << "
    ";
        }
        return 0;
    }
    

    D. Kavi on Pairing Duty

    题解

    假设点 (1)(x) 配对,根据 (x)(n) 的大小关系可以分为以下两种情况:

    (x > n)

    • 此时 (x + 1) 由于不被 ([1,x]) 包含,只能与 (2) 配对。

    • 同理, ([x, 2n]) 间的点只能依次与 ([1, 1 + 2n - x]) 配对。

    • 此时在 ((1 + 2n - x, x)) 中还有 (2(x - n - 1)) 个点,即余下的点总为 (2) 的倍数,所以可以设 (dp_i)(2i) 个点时的方案数。

    • (x) 取大于 (n)(n+1, n+2,dots,2n) 时,余下的点依次为 (2 imes (0,1,dots,n-1)) 个,由于这些点被所有区间包含,所以只需考虑它们自身即可。即,当 (x > n) 时,总的方案数之和为 (sum limits _{i = 0}^{n - 1} dp_i)

    (x le n)

    • 此时 (x + 1) 可以与 (2)(2x) 配对。若 (x + 1)(2x) 配对,由于 (2) 不被 ([x + 1, 2x]) 包含所以必须与 (x + 1) 配对,矛盾,所以 (x + 1) 仍只能与 (2) 配对。

    • 同理, ([x, 2(x - 1)]) 间的点只能依次与 ([1, x - 1]) 配对。

    • 此时 (2n) 个点被分割成了一个个长为 (2(x - 1)) 的小整体,所以 (x - 1) 需要整除 (n) ,又由于 (x - 1 le n - 1) ,所以共有 (n) 的真因子个数种分法。即 (x le n) 的情况共有 (div_n) 种分法。

    综上,推得 (dp_n = div_n + sum limits _{i = 0}^{n - 1} dp_i)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        constexpr int N = 1e6 + 10;
        vector<int> div(N);
        for (int i = 1; i < N; i++) {
            for (int j = i + i; j < N; j += i) {
                ++div[j];
            }
        }
        constexpr int MOD = 998244353;
        vector<int> dp(N);
        int sum = dp[0] = 1;
        for (int i = 1; i < N; i++) {
            dp[i] = (div[i] + sum) % MOD;
            sum = (sum + dp[i]) % MOD;
        }
        int n;
        cin >> n;
        cout << dp[n] << "
    ";
        return 0;
    }
    

    E. Trees of Tranquillity

    题解

    由于构造图为完全图,所以其中的点在树一中两两存在父子关系,即在树一中为一条链,所以可以用 (dfs) 回溯遍历树一中的链。

    为了快速判断两点在树二上是否存在父子关系,可以用 (dfs) 序打时间戳,若 (v)(u) 的子代,则一定有 (in_u < in_v < out_u) ,同时,由于贪心策略,若两点在树二中存在父子关系,取子结点更优。

    代码

    #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;
            cin >> n;
            vector<vector<int>> G1(n);
            for (int v = 1; v < n; v++) {
                int u;
                cin >> u;
                --u;
                G1[u].push_back(v);
            }
            vector<vector<int>> G2(n);
            for (int v = 1; v < n; v++) {
                int u;
                cin >> u;
                --u;
                G2[u].push_back(v);
            }
            vector<int> in(n), out(n), id(n);
            int timeStamp = 0;
            function<void(int)> dfsG2 = [&](int u) {
                in[u] = timeStamp++;
                id[in[u]] = u;
                for (auto v : G2[u]) {
                    dfsG2(v);
                }
                out[u] = timeStamp;
            };
            dfsG2(0);
            int ans = 0;
            set<int> st;
            function<void(int)> dfsG1 = [&](int u) {
                bool add = false;
                int del = -1;
                auto it = st.upper_bound(in[u]);
                if (it != st.end() and *it < out[u]) { //若 set 中已有子结点,由贪心策略,取子结点更优
                    
                } else {
                    if (it != st.begin()) {
                        --it;
                        if (out[id[*it]] > in[u]) { //同上, erase 掉父结点
                            del = *it;
                            st.erase(it);
                        }
                    }
                    st.insert(in[u]);
                    add = true;
                }
                ans = max(ans, (int)st.size());
                for (auto v : G1[u]) {
                    dfsG1(v);
                }
                if (add) {
                    st.erase(in[u]);
                    if (del != -1) {
                        st.insert(del);
                    }
                }
            };
            dfsG1(0);
            cout << ans << "
    ";
        }
        return 0;
    }
    

    F. It's a bird! No, it's a plane! No, it's AaParsa!

    题解

    本质上还是最短路问题,只不过多出了每个点等待的时间。

    由于点的个数 (n) 远少于边数 (m) ,所以采用 (O_{(n^2)})(Dijkstra)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n, m;
        cin >> n >> m;
        vector<vector<pair<int, int>>> G(n);
        for (int i = 0; i < m; i++) {
            int u, v, w;
            cin >> u >> v >> w;
            G[u].emplace_back(v, w);
        }
        const int INF = 1e9 + n;
        for (int s = 0; s < n; s++) {
            vector<int> dis(n, INF);
            vector<bool> vis(n);
            for (auto [v, w] : G[s]) {
                dis[v] = w;
            }
            for (int loop = 0; loop < n; loop++) {
                int u = -1;
                for (int i = 0; i < n; i++) {
                    if (vis[i]) {
                        continue;
                    }
                    if (u == -1 or dis[i] < dis[u]) {
                        u = i;
                    }
                }
                vis[u] = true;
                for (int wait = 0; wait < n; wait++) {
                    dis[(u + wait) % n] = min(dis[(u + wait) % n], dis[u] + wait);
                } //其实只考虑每个点等 1 秒的情况即可,和等 n 秒的情况是等价的
                for (auto [v, w] : G[u]) {
                    dis[(v + dis[u]) % n] = min(dis[(v + dis[u]) % n], w + dis[u]);
                }
            }
            dis[s] = 0;
            for (int i = 0; i < n; i++) {
                cout << dis[i] << " 
    "[i == n - 1];
            }
        }
        return 0;
    }
    
  • 相关阅读:
    scala学习笔记:理解stream和view
    scala学习笔记:变量声明中的模式
    scala学习笔记:理解并行集合par
    快速了解Scala技术栈
    scala学习笔记:控制抽象
    scala中的call-by-name和call-by-value
    scala学习笔记:各种奇怪的写法
    scala学习笔记:match与unapply()
    scala学习笔记:无参函数
    scala学习笔记:函数与方法
  • 原文地址:https://www.cnblogs.com/Kanoon/p/14842534.html
Copyright © 2011-2022 走看看