CSP-J 2024 题解

本文链接

CSP-J 2024 扑克牌

用 set 可以轻松判断扑克牌的种类数,然后用 52 减去它

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    set<string> s;
    while(n--) {
        string c;
        cin >> c;
        s.insert(c);
    }

    cout << 52 - s.size() << '\n';
}

CSP-J 2024 地图探险

比较常规的模拟题,唯一需要注意的是结束/开始时的位置要加入统计

#include <bits/stdc++.h>
using namespace std;

int main() {
    int t;
    cin >> t;

    auto solve = []() {
        int n, m, k;
        cin >> n >> m >> k;
        int x, y, d;
        cin >> x >> y >> d;
        x--, y--;

        vector<string> a(n);
        for (int i = 0; i < n; i++) cin >> a[i];

        vector vis(n, vector<int>(m));
        int ans = 0;
        while (k--) {
            if (!vis[x][y]) {
                ans++;
                vis[x][y] = 1;
            }
            int nx = x, ny = y;
            if (d == 0) ny++;
            if (d == 1) nx++;
            if (d == 2) ny--;
            if (d == 3) nx--;
            if (nx >= 0 && nx < n && ny >= 0 && ny < m && a[nx][ny] == '.') {
                x = nx, y = ny;
            } else {
                d = (d + 1) % 4;
            }
        }
        if (!vis[x][y]) ans++;

        cout << ans << '\n';
    };

    while (t--) solve();
}

CSP-J 2024 小木棍

很有意思的贪心和模拟题。首先要自己列出0-9需要的木棍数,发现8是最占用木棍的,假如木棍很多那肯定大部分数是8,这样拼出来的数数位最少。顺着这个思路,我们可以先确定拼出来的数的数位是 \(\lceil \frac{k}{7} \rceil\)。确定好数位了,我们就从头到尾贪心地取“能取的最小值”,所谓“能取的最小值”其实就是确保后面的数也可以组出一个合法的数字。具体的条件见代码。

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    const vector<int> cost = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};

    int t;
    cin >> t;

    auto solve = [&]() {
        int n;
        cin >> n;

        if (n == 1) {
            cout << "-1\n";
            return;
        }

        int k = (n + 6) / 7;
        string ans;
        for (int i = 0; i < k; i++) {
            int left = k - i - 1;
            int start = int(i == 0);
            for (int j = start; j <= 9; j++) {
                int after = n - cost[j];
                if ((!left && !after) ||
                    (left && after >= 2 * left && after <= 7 * left)) {
                    ans += char('0' + j);
                    n = after;
                    break;
                }
            }
        }

        cout << ans << '\n';
    };

    while (t--) solve();
}

CSP-J 2024 接龙

老实讲这题真是难到我了。第一眼看过去很容易被唬住。其实本质是个按轮数递推的 DP,但状态设计非常考验对冗余信息的剥离。

题目最烦的限制是“相邻两轮不能是同一个人”。如果按部就班地用 set 记录“到底有哪几个人能凑出数字 x”,状态和转移都会爆炸。

但仔细一想有个核心性质:如果上一轮凑出数字 x 的人 \(\ge 2\),那下一轮任何人都可以接(因为总能挑到一个不是自己的前驱)。
所以状态直接降维,dp[i][x] 只需要存三种值:

  • -1:没人能凑出。
  • p:只有玩家 p 一个人能凑出(下一轮 p 不能接)。
  • -2:有两人及以上能凑出(下一轮谁都能接,百搭状态)。

另外,转移时如果每次回头找 \(k-1\) 个数肯定会 TLE。其实只要在遍历序列时,顺手维护一个 last_valid_pos(最近一次出现的合法开头位置)就行了。只要当前位置和它的距离 \(\le k\),就能作为这一轮的结尾。

时间复杂度 \(O(R \times \sum L)\)

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;

    auto solve = []() {
        int n, k, q;
        cin >> n >> k >> q;

        vector<vector<int>> s(n);
        int max_val = 0;
        for (int i = 0; i < n; i++) {
            int len;
            cin >> len;
            while (len--) {
                int x;
                cin >> x;
                x--;
                s[i].push_back(x);
                max_val = max(max_val, x);
            }
        }

        auto upd = [](int& x, int y) {
            if (x == -1)
                x = y;
            else if (x >= 0 && x != y)
                x = -2;
        };

        vector dp(101, vector<int>(max_val + 1, -1));
        // dp[i][j]: 第 i 轮转移是以数字 j 结尾的状态
        // p: 第 p 个人可以提供, -1: 无人提供, -2: 超过两个人可以提供
        dp[0][0] = -2;
        for (int i = 1; i <= 100; i++) {
            for (int j = 0; j < n; j++) {
                int last_valid_pos = -1;
                for (int x = 0; x < s[j].size(); x++) {
                    if (last_valid_pos != -1 && x - last_valid_pos + 1 <= k) {
                        upd(dp[i][s[j][x]], j);
                    }
                    if (dp[i - 1][s[j][x]] == -2 ||
                        (dp[i - 1][s[j][x]] >= 0 && dp[i - 1][s[j][x]] != j))
                        last_valid_pos = x;
                }
            }
        }

        while (q--) {
            int r, c;
            cin >> r >> c;
            c--;
            if (c > max_val) {
                cout << "0\n";
            } else {
                cout << int(dp[r][c] != -1) << '\n';
            }
        }
    };

    while (t--) solve();
}
posted @ 2026-05-28 09:38  Linqi05  阅读(8)  评论(0)    收藏  举报