CCPC 2021 四川省赛

A. Chuanpai

题目大意

\(1 \leq x,y \leq 6\),问有多少组x+y=k

解题思路

暴力模拟即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        int k, ans = 0;
        std::cin >> k;

        for (int x = 1; x <= 6; x++) {
            for (int y = x; y <= 6; y++) {
                ans += x + y == k;
            }
        }

        std::cout << ans << "\n";
    }
}

K. K-skip Permutation

题目大意

给定n和k,要求构造一个n排列p使得\(p_i+k=p_{i+1}\)的数量尽可能多

解题思路

对每一个位置都尽可能一直找+k即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;
const int N = 2e6 + 10;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int n, k;
    std::cin >> n >> k;

    std::vector<int> f(N), ans;
    for (int i = 1; i <= n; i++) {
        int x = i;
        while (!f[x] && x <= n) {
            f[x] = 1;
            ans.emplace_back(x);
            x += k;
        }
    }
    for (int i = 0; i < n; i++) {
        if (i != n - 1)
            std::cout << ans[i] << " ";
        else
            std::cout << ans[i];
    }
}

H. NihongowaMuzukashiiDesu

题目大意

给定单词和变形规则,给出原单词,求变形单词

解题思路

按照题意模拟即可

代码实现

for _ in range(int(input())):
    s = input()
    if s == "ikimasu":
        print("itte")
    elif s[-7:] == "shimasu":
        print(s[:-7] + "shite")
    elif s[-6:] == "gimasu":
        print(s[:-6] + "ide")
    elif s[-6:] == "kimasu":
        print(s[:-6] + "ite")
    elif s[-6:] in ["mimasu", "bimasu", "nimasu"]:
        print(s[:-6] + "nde")
    elif s[-7:] == "chimasu":
        print(s[:-7] + "tte")
    elif s[-6:] == "rimasu":
        print(s[:-6] + "tte")
    elif s[-5:] == "imasu":
        print(s[:-5] + "tte")

B. Hotpot

题目大意

n个人吃火锅,如果里面有他喜欢的食物则吃光然后幸福值+1,否则加入他喜欢的食物,每个人喜欢的食物都是唯一的循环操作m次这样的操作,问最后每个人的幸福值是多少

解题思路

显然2n步之后会回到初始状态,对于循环部分直接模拟计算,不完整的循环单独计算即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n, k, m;
        std::cin >> n >> k >> m;

        std::vector<int> a(n), aa(n), bb(n), ans(n), f(k + 1);
        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
            if (f[a[i]]) {
                f[a[i]] = 0;
                aa[i]++;
            } else {
                f[a[i]] = 1;
            }
        }
        bb = aa;
        
        for (int i = 0; i < n; i++) {
            if (f[a[i]]) {
                f[a[i]] = 0;
                bb[i]++;
            } else {
                f[a[i]] = 1;
            }
        }
        
        if (m / (2 * n)) {
            for (int i = 0; i < n; i++) {
                ans[i] += m / (2 * n) * bb[i];
            }
            m = m % (2 * n);
        }

        if (m / n) {
            for (int i = 0; i < n; i++) {
                if (f[a[i]]) {
                    f[a[i]] = 0;
                    ans[i]++;
                } else {
                    f[a[i]] = 1;
                }
            }
            m = m % n;
        }

        for (int i = 0; i < m; i++) {
            if (f[a[i]]) {
                f[a[i]] = 0;
                ans[i]++;
            } else {
                f[a[i]] = 1;
            }
        }
        
        for (int i = 0; i < n; i++) {
            std::cout << ans[i] << " \n"[i == n - 1];
        }
    }
}

D. Rock Paper Scissors

题目大意

b和d进行石头剪刀布游戏,输-1平0赢+1,每次b先手,b要最小化分数,d要最大化分数,两人都是聪明的,问最后的得分是多少

解题思路

先手显然影响不了比赛,只要最大分数是多即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        i64 b1, b2, b3, d1, d2, d3, ans = 0;
        std::cin >> b1 >> b2 >> b3 >> d1 >> d2 >> d3;

        i64 x1 = std::min(b1, d2), x2 = std::min(b2, d3), x3 = std::min(b3, d1);
        ans += x1 + x2 + x3;

        b1 -= x1;
        b2 -= x2;
        b3 -= x3;
        d1 -= x3;
        d2 -= x1;
        d3 -= x2;

        x1 = std::min(b1, d1);
        x2 = std::min(b2, d2);
        x3 = std::min(b3, d3);

        b1 -= x1;
        b2 -= x2;
        b3 -= x3;
        d1 -= x3;
        d2 -= x1;
        d3 -= x2;

        ans -= b1 + b2 + b3;

        std::cout << ans << "\n";
    }
}

M. True Story

题目大意

给你n个人的速度,告诉你所有飞机延迟的时刻和延迟的时间,再给定最初的到机场的距离和登机时间,问有多少人能登机

解题思路

只要找到延时最久的飞机需要的时间即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int n, k, x, p0, ans = 0;
    std::cin >> n >> k >> x >> p0;

    std::vector<int> s(n), t(k), p(k);
    for (int i = 0; i < n; i++) {
        std::cin >> s[i];
    }
    for (int i = 0; i < k; i++) {
        std::cin >> t[i];
    }
    for (int i = 0; i < k; i++) {
        std::cin >> p[i];
    }

    double v = x / p0;
    for (int i = 0; i < k; i++) {
        v = std::min(v, (double)x / (double)(p[i] - t[i]));
    }
    for (int i = 0; i < n; i++) {
        if (s[i] >= v) {
            ans++;
        }
    }

    std::cout << ans << "\n";
}

L. Spicy Restaurant

题目大意

给你一张无向图,每个节点表示一个餐厅,点权代表餐厅辛辣值,再告诉你q个游客所在的餐厅和他能接受的辛辣值,求第i名游客和他可以接受辛辣值的最近餐厅

解题思路

注意到辛辣值的范围很小,因此可以考虑从辛辣值入手进行bfs,最后对每个游客能接受的辛辣值都检查一遍即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int n, m, q;
    std::cin >> n >> m >> q;

    std::vector<std::array<int, 2>> W(n + 1);
    for (int i = 1; i <= n; i++) {
        std::cin >> W[i][0];
        W[i][1] = i;
    }
    sort(W.begin(), W.end());

    std::vector<std::vector<int>> g(n + 1), vis(101, std::vector<int>(n + 1));
    for (int i = 1; i <= m; i++) {
        int u, v;
        std::cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    std::queue<std::array<int, 3>> que;
    for (int i = 1; i <= n; i++) {
        auto [w, u] = W[i];
        que.push({w, u, 0});
    }

    while (!que.empty()) {
        auto [w, u, dist] = que.front();
        que.pop();
        if (vis[w][u]) {
            continue;
        }
        if (dist) {
            vis[w][u] = dist;
        } else {
            vis[w][u] = -1;
        }
        for (auto v : g[u]) {
            if (!vis[w][v]) {
                que.push({w, v, dist + 1});
            }
        }
    }

    while (q--) {
        int p, a, ans = INT_MAX;
        std::cin >> p >> a;

        for (int i = 1; i <= a; i++) {
            if (vis[i][p]) {
                ans = std::min(ans, vis[i][p]);
            }
        }

        if (ans == -1) {
            std::cout << 0 << "\n";
        } else if (ans == INT_MAX) {
            std::cout << -1 << "\n";
        } else {
            std::cout << ans << "\n";
        }
    }
}

E. Don’t Really Like How The Story Ends

题目大意

给你一张无向图,问要补多少条边才能使得dfs的结果为1~n

解题思路

由于要1~n,因此只用建从小到大的边即可,之后对着这张图进行dfs,统计已经正确变量的数量cnt,如果u连边刚好是cnt+1说明可以直接继续搜索,如果大于cnt+1说明缺少了到cnt+1的边,这时候需要补一条边并回溯一次,看是否需要多次补边,最后在每个联通分量之间都进行一次连接即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n, m;
        std::cin >> n >> m;

        std::vector<std::vector<int>> g(n + 1);
        std::set<std::array<int, 2>> st;
        while (m--) {
            int u, v;
            std::cin >> u >> v;
            if (u > v) {
                std::swap(u, v);
            }
            if (u == v || st.count({u, v})) {
                continue;
            }
            st.insert({u, v});
            g[u].push_back(v);
        }

        int cnt = 1, ans = 0;
        for (auto &v : g) {
            sort(v.begin(), v.end());
        }
        std::vector<int> vis(n + 1);

        auto dfs = [&](auto &&self, int u) -> void {
            if (vis[u]) {
                return;
            }
            vis[u] = 1;
            if (u >= n) {
                return;
            }
            for (int i = 0; i < g[u].size(); i++) {
                auto v = g[u][i];
                if (v == cnt + 1) {
                    cnt++;
                    self(self, v);
                } else if (v > cnt + 1) {
                    cnt++;
                    ans++;
                    self(self, cnt);
                    i--;
                }
            }
            return;
        };

        for (int i = 1; i <= n; i++) {
            if (!vis[i]) {
                dfs(dfs, i);
                ans++;
                cnt++;
            }
        }

        std::cout << ans - 1 << "\n";
    }
}
posted @ 2025-07-04 18:05  udiandianis  阅读(20)  评论(0)    收藏  举报