CSP-J 2025 题解

本文链接

CSP-J 2025 拼数

要把数字拼成最大的正整数,其实就是把所有数字从大到小排序输出。
代码里用 map 统计数字出现的次数,然后从后往前(逆序)输出即可。因为题目保证至少有一个非零数字,所以完全不用担心开头是 \(0\) 的情况。

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

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

    string s;
    cin >> s;

    map<char, int> mp;
    for (auto c : s) {
        if (isdigit(c)) mp[c]++;
    }

    for (auto ite = mp.rbegin(); ite != mp.rend(); ite++) {
        while (ite->second--) cout << ite->first;
    }
    cout << '\n';
}

CSP-J 2025 座位

排序求出小R的排名,然后根据蛇形填充规则算出对应的列和行(奇数列正序、偶数列倒序)。

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

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

    int n, m;
    cin >> n >> m;

    int N = n * m;
    vector<int> a(N);
    for (int i = 0; i < N; i++) {
        cin >> a[i];
    }

    int a0 = a[0];
    sort(a.begin(), a.end());
    int rk = N - (lower_bound(a.begin(), a.end(), a0) - a.begin()) - 1;

    int q = rk / n, r = rk % n;
    if (q & 1) r = n - 1 - r;

    cout << q + 1 << ' ' << r + 1 << '\n';
}

CSP-J 2025 异或和

贪心,从左往右扫,维护当前段的前缀异或集合。每次发现当前前缀异或能和集合中某个值异或得到k,说明找到一个合法段,立刻切割并清空集合重新开始。能切就切是最优的,因为早切不会让后面的选择变少。

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

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

    int n, k;
    cin >> n >> k;

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

    set<int> s;
    s.insert(0);
    auto s0 = s;
    int ans = 0;
    for (int i = 0, cur = 0; i < n; i++) {
        cur ^= a[i];
        if (s.count(cur ^ k)) {
            ans++;
            cur = 0;
            s = s0;
        } else {
            s.insert(cur);
        }
    }
    cout << ans << '\n';
}

CSP-J 2025 多边形

先排序。排完序后枚举每根木棍 \(a_i\) 作为最大边,前面 \(i\) 根随便选,总共 \(2^i\) 种选法(含空集)。不合法的情况是前面选出来的和 \(\le a_i\),用 01 背包维护前 \(i-1\) 根的子集和分布即可快速统计。

具体来说,设 \(f[j]\) 为前面若干根木棍中选出总和恰为 \(j\) 的方案数,初始 \(f[0]=1\)。对第 \(i\) 根木棍,不合法方案数为 \(\sum_{j=0}^{a_i} f[j]\)(这里 \(j=0\) 对应前面啥都不选,即只有 \(a_i\) 一根,边数不够 3,确实不合法)。合法贡献就是 \(2^i - \sum_{j=0}^{a_i} f[j]\),累加到答案里,然后把 \(a_i\) 扔进背包。

复杂度 \(O(n \cdot \sum a_i)\)\(\sum a_i \le 5000\) 所以随便跑。

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

const int mod = 998244353;
int norm(int x) {
    if (x < 0) {
        x += mod;
    }
    if (x >= mod) {
        x -= mod;
    }
    return x;
}
template <class T>
T power(T a, i64 b) {
    T res = 1;
    for (; b; b /= 2, a *= a) {
        if (b % 2) {
            res *= a;
        }
    }
    return res;
}
struct Z {
    int x;
    Z(int _x = 0) : x(norm(_x)) {}
    Z(i64 _x) : x(norm(_x % mod)) {}
    int val() const { return x; }
    Z operator-() const { return Z(norm(mod - x)); }
    Z inv() const {
        assert(x != 0);
        return power(*this, mod - 2);
    }
    Z& operator*=(const Z& rhs) {
        x = i64(x) * rhs.x % mod;
        return *this;
    }
    Z& operator+=(const Z& rhs) {
        x = norm(x + rhs.x);
        return *this;
    }
    Z& operator-=(const Z& rhs) {
        x = norm(x - rhs.x);
        return *this;
    }
    Z& operator/=(const Z& rhs) { return *this *= rhs.inv(); }
    friend Z operator*(const Z& lhs, const Z& rhs) {
        Z res = lhs;
        res *= rhs;
        return res;
    }
    friend Z operator+(const Z& lhs, const Z& rhs) {
        Z res = lhs;
        res += rhs;
        return res;
    }
    friend Z operator-(const Z& lhs, const Z& rhs) {
        Z res = lhs;
        res -= rhs;
        return res;
    }
    friend Z operator/(const Z& lhs, const Z& rhs) {
        Z res = lhs;
        res /= rhs;
        return res;
    }
};

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

    int n;
    cin >> n;

    vector<int> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    sort(a.begin(), a.end());

    vector<Z> f(5001);  // f[i] 表示和为 i 的合法方案
    f[0] = 1;

    Z ans = 0;
    for (int i = 0; i < n; i++) {
        Z invalid = 0;
        for (int j = 0; j <= a[i]; j++) invalid += f[j];

        ans += power(Z(2), i) - invalid;

        // 本身 a[i] 也放进背包
        for (int j = 5000; j >= a[i]; j--) f[j] += f[j - a[i]];
    }
    cout << ans.val() << '\n';
}

这里用 power 的时候记得给 2 也套个 Z,jiangly 模板用的还是不熟练

posted @ 2026-05-24 10:47  Linqi05  阅读(13)  评论(0)    收藏  举报