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()];
}
}
}

浙公网安备 33010602011771号