CCPC 2024 吉林省赛

I. The Easiest Problem

题目大意

给你一句话,问有多少个小写字母

解题思路

数一下小写字母数量即可

代码实现

s = input()
ans = 0
for i in s:
    ans += i.islower()
print(ans)

L. Recharge

题目大意

有容量为k的电池,能充x次一格电和y次两格电,当剩余电量为k-1的时候,两次充电都只能充一格,问最多能充满多少个电池

解题思路

显然差1充满的时候充两格电时存在浪费操作,所以避免浪费直接贪心,对k判断奇偶分别处理尽可能不浪费即可,特判k为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--) {
        i64 k, x, y, ans = 0;
        std::cin >> k >> x >> y;

        if (k == 1) {
            std::cout << x + y << "\n";
            continue;
        }

        i64 cnt = k / 2;
        if (k % 2) {
            i64 minn = std::min(y / cnt, x);
            ans += minn;
            x -= minn;
            y -= minn * cnt;
            if (y < cnt) {
                ans += (2 * y + x) / k;
            } else {
                ans += y / (cnt + 1);
            }
        } else {
            ans += y / cnt;
            y %= cnt;
            ans += (2 * y + x) / k;
        }

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

G. Platform Game

题目大意

二维坐标中有很多线段,给定初始位置,如果触碰线段就沿着线段朝x轴正方向移动,否则朝y轴负方向移动,问触碰到x轴的时候的位置

解题思路

按照y轴降序,判断线段与当前位置的关系,不断模拟即可

代码实现

#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;
        std::cin >> n;

        std::vector<std::array<int, 3>> yrl(n);
        for (int i = 0; i < n; i++) {
            std::cin >> yrl[i][2] >> yrl[i][1] >> yrl[i][0];
        }

        std::sort(yrl.begin(), yrl.end(), std::greater<>());

        int stx, sty;
        std::cin >> stx >> sty;

        for (auto [y, r, l] : yrl) {
            if (y <= sty && l < stx && r > stx) {
                stx = r;
                sty = y;
            }
        }

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

E. Connected Components

题目大意

给定n组ab,如果满足 \(a_i - a_j \leq i - j \leq b_i - b_j\)\(a_j - a_i \geq j - i \geq b_i - b_j\),则ij联通,问有多少连通块

解题思路

先对不等式变形,得到 \(a_i - i \leq a_j - j\)\(i - b_i \leq j - b_j\),对 \(a_i - i\)排序,之后只关心 \(i - b_i\),用单调栈维护之前每个连通块的最小 \(i - b_i\) 即可

代码实现

#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;
    std::cin >> n;

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

    std::map<int, int> mp;
    for (auto [x, y] : ab) {
        int siz = stk.size(), xmaxn = x, ymaxn = y, cnt = 0;
        while (siz) {
            if (y <= stk[siz - 1][1] || x == stk[siz - 1][0] || mp[x] && cnt == 0) {
                if (stk[siz - 1][1] > ymaxn) {
                    ymaxn = stk[siz - 1][1];
                    xmaxn = stk[siz - 1][0];
                }
                stk.erase(stk.begin() + siz--);
                cnt++;
            } else {
                break;
            }
        }
        stk.push_back({xmaxn, ymaxn});
        mp[x]++;
    }

    std::cout << stk.size() << "\n";
}

D - Parallel Lines

题目大意

给n个点,找出k条平行线,输出每条线上点的数量和索引

解题思路

如果已知斜率k,那么nlogn扫描一次即可得知所有点是不是能存在于这个斜率的直线,而k非常小,随机ij获得正确斜率的期望为1/k,期望复杂度为knlogn,可以通过本题

代码实现

#include <bits/stdc++.h>

using i64 = long long;

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

    std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());

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

    std::vector<i64> X(n), Y(n);
    std::map<i64, std::vector<int>> B;
    for (int i = 0; i < n; i++) {
        std::cin >> X[i] >> Y[i];
    }

    while (true) {
        int p1 = 0;
        int p2 = std::uniform_int_distribution<int>(0, n - 1)(rng);
        int g = std::__gcd(X[p1] - X[p2], Y[p1] - Y[p2]);
        if (g) {
            i64 x = (X[p1] - X[p2]) / g, y = (Y[p1] - Y[p2]) / g;
            for (int i = 0; i < n; i++) {
                B[Y[i] * x - y * X[i]].push_back(i + 1);  // 如果有k条线,那么就有k个常数b
            }
            if (B.size() == k) {
                break;
            } else {
                B.clear();
            }
        }
    }

    for (auto [_, v] : B) {
        std::cout << v.size() << " ";
        for (auto num : v) {
            std::cout << num << " \n"[num == v.back()];
        }
    }
}
posted @ 2025-04-18 15:04  udiandianis  阅读(204)  评论(0)    收藏  举报