Skip to content

2026夏个人训练赛第二十四场

A. 贪吃巧克力

  • 双指针
  • 模拟

直接两边同时模拟。

cpp
#include <iostream>

using namespace std;

typedef long long LL;
const int N = 1000010;
LL a[N];

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int _; cin >> _;
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    int l = 1, r = n;
    for (int i = 1; i <= m; ++i) {
        LL p, x;
        int j, k = r - l + 1;
        cin >> p >> x;
        bool f = false;
        for (j = 0; j <= r - l; ++j) {
            LL lx = a[l + j] * (a[l + (j + p) % k]);
            LL rx = a[l + k - j - 1] * a[l + (k - j - 1 + p) % k];
            if (lx == x) {
                cout << "L " << j + 1 << '\n';
                l += j + 1;
                f = true;
                break;
            }
            else if (rx == x) {
                cout << "R " << j + 1 << '\n';
                r -= j + 1;
                f = true;
                break;
            }
        }
        if (!f) cout << "F\n";
    }
    return 0;
}

B. 好串串

  • 动态规划
  • 字符串

考虑从左到右枚举当前位置为结尾的好串,发现只能是一种包含两个以上不同字符的串,和所有相邻的相同字符的串。对于第一个预处理一个左侧的下标(极大的好串是一定不会互相包含,而且即使重叠重叠的部分分给哪边都是一样的,所以可以 O(n) 预处理),对于第二个 DP 的时候按段维护一下前缀 min.

cpp
#include <iostream>

using namespace std;

const int N = 5000010;
int f[N], g[N];
int tr[N * 4];

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int _, T;
    cin >> _ >> T;
    while (T--) {
        string s;
        cin >> s;
        int n = s.length();
        s = " " + s;
        
        fill(f, f + n + 1, n);
        fill(g, g + n + 1, n + 1);
        f[0] = 0;

        for (int i = 1; i <= n; ) {
            int j = i;
            while (j <= n && s[j + 1] == s[i]) j++;
            int l = i - 1, r = j + 1;
            while (l >= 1 && r <= n && s[l] == s[r] && s[l] <= s[l + 1]) {
                g[r] = min(g[r], l);
                l--, r++;
            }
            i = r;
        }
        
        int pre = 0;

        for (int i = 1; i <= n; ++i) {
            if (s[i] == s[i - 1]) pre = min(pre, f[i - 1]);
            else pre = f[i - 1];
            f[i] = pre + 1;
            if (g[i] < i) f[i] = min(f[i], f[g[i] - 1] + 1);
        }

        cout << f[n] << '\n';
    }
    return 0;
}

C. 行走

  • 广度优先搜索
  • 数论

暴力所有的约数。

cpp
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 1010;

bool vis[N][N];
int a[N][N];

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n, v, res = 1;
    cin >> n >> v;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) cin >> a[i][j];
    }
    v = a[1][1];
    int l = sqrt(v);
    vector<int> s = {v};
    for (int i = 2; i <= l; ++i) {
        if (v % i == 0) {
            s.emplace_back(i);
            if (i * i != v) s.emplace_back(v / i);
        }
    }
    sort(s.begin(), s.end(), greater<int>());
    for (int t : s) {
        fill(vis[0], vis[0] + N * N, false);
        queue<pair<int, int>> q;
        q.emplace(1, 1);
        vis[1][1] = true;
        while (!q.empty()) {
            auto [x, y] = q.front();
            q.pop();
            if (x == n && y == n) {
                res = t;
                break;
            }
            if (x < n && a[x + 1][y] % t == 0 && !vis[x + 1][y]) vis[x + 1][y] = true, q.emplace(x + 1, y);
            if (y < n && a[x][y + 1] % t == 0 && !vis[x][y + 1]) vis[x][y + 1] = true, q.emplace(x, y + 1);
        }
        if (res == t) break;
    }
    cout << res << '\n';
    return 0;
}

E. 真实排名

  • 组合数学
  • 数学

特判一下 0,因为翻倍也无效。对于任意一个 Ai 不是 0 的人。

  • 不翻倍,那么比他大的和严格小于 Ai2 的里面任选 k 个即可。
  • 翻倍,那么 [Ai,2Ai) 都需要翻倍,假设固定要翻倍 t 个,在剩下的里面再任选 k - t 个即可。
cpp
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef long long LL;
const int MOD = 998244353;
const int N = 100010;

LL fac[N], inv[N];

LL power(LL n, LL p) {
    LL res = 1, base = n;
    while (p) {
        if (p & 1) res = res * base % MOD;
        base = base * base % MOD;
        p >>= 1;
    }
    return res;
}

void init() {
    int n = 100000;
    fac[0] = inv[0] = 1;
    for (int i = 1; i <= n; ++i) fac[i] = fac[i - 1] * i % MOD;
    inv[n] = power(fac[n], MOD - 2);
    for (int i = n - 1; i; --i) inv[i] = inv[i + 1] * (i + 1) % MOD;
}

LL comb(LL n, LL m) {
    if (n < m) return 0;
    return fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}

vector<LL> values;
LL a[N], s[N], res[N], m;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    init();
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        values.emplace_back(a[i]);
    }
    sort(values.begin(), values.end());
    values.erase(unique(values.begin(), values.end()), values.end());
    m = values.size();
    for (int i = 1; i <= n; ++i) {
        s[lower_bound(values.begin(), values.end(), a[i]) - values.begin() + 1] ++;
    }
    for (int i = 1; i <= m; ++i) {
        s[i] += s[i - 1];
    }
    for (int i = 1; i <= m; ++i) {
        if (values[i - 1] == 0) {
            res[i] = comb(n, k);
            continue;
        }
        LL cur = 0;
        // no 
        int big = s[m] - s[i - 1] - 1, small = s[upper_bound(values.begin(), values.end(), values[i - 1] - 1 >> 1) - values.begin()];
        cur = comb(big + small, k);
        // yes
        int t = s[lower_bound(values.begin(), values.end(), values[i - 1] * 2) - values.begin()] - s[i - 1];
        if (k >= t) cur = (cur + comb(n - t, k - t)) % MOD;
        res[i] = cur;
    }
    for (int i = 1; i <= n; ++i) {
        cout << res[lower_bound(values.begin(), values.end(), a[i]) - values.begin() + 1] << '\n';
    }
    return 0;
}

F. 甲苯先生的字符串

  • 快速幂
  • 动态规划

只有相邻两位有约束,而且是线性的,直接矩阵快速幂 O(263logn)

cpp
#include <iostream>
#include <cstring>

using namespace std;

typedef long long LL;
const int N = 26;
const int MOD = 1000000007;

LL a[N][N], b[N][N];
LL v1[N], v2[N];

void mul1() {
    memset(v2, 0, sizeof(v2));
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            v2[i] = (v2[i] + v1[j] * a[j][i]) % MOD;
        }
    }
    memcpy(v1, v2, sizeof(v1));
}

void mul2() {
    memset(b, 0, sizeof(b));
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            for (int k = 0; k < N; ++k) {
                b[i][j] = (b[i][j] + a[i][k] * a[k][j]) % MOD;
            }
        }
    }
    memcpy(a, b, sizeof(a));
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    LL p;
    string s;
    cin >> p >> s;
    fill(a[0], a[0] + N * N, 1);
    fill(v1, v1 + N, 1);
    for (int i = 1; i < s.length(); ++i) {
        a[s[i - 1] - 'a'][s[i] - 'a'] = 0;
    }
    p--;
    while (p) {
        if (p & 1) mul1();
        mul2();
        p >>= 1;
    }
    LL res = 0;
    for (int i = 0; i < N; ++i) res = (res + v1[i]) % MOD;
    cout << res << '\n';
    return 0;
}

其他没做的题

  • 构造题
  • Eddy Walker
  • Eddy Walker 2
  • Go on Strike!
  • Kth Minimum Clique
  • MAZE