- 本篇中的题目顺序为预期难度顺序,并非比赛题目顺序
- 本篇中所有的“更好的优化”均为标准答案之外的思考,不使用此内容也可以通过题目
本文为拷贝版本,可能存在图片丢失等问题,不修复,请前往原地址查看
比赛预期情况
总共比赛人数:175 (至少通过一道题的人数,没有通过题的不计入总人数)
| 题目名 | 实际通过次数 | 实际通过比例 | 预期通过比例 |
|---|---|---|---|
| chiking 的偶像 | “EDIT” | “EDIT” | 100% |
| chiking 和珂朵莉 | “EDIT” | “EDIT” | 80% |
| chiking 的序列 II | “EDIT” | “EDIT” | 60% |
| chiking 的序列 I | “EDIT” | “EDIT” | 50% |
| chiking 的棋盘 | “EDIT” | “EDIT” | 30% |
| 乐于助人的 chiking | “EDIT” | “EDIT” | 20% |
| chiking 的俄罗斯方块 | “EDIT” | “EDIT” | 1% |
| chiking 和大家一起来做签到题 | “EDIT” | “EDIT” | 1% |
| chiking 是一个机器人 | “EDIT” | “EDIT” | 1% |
P.S. “EDIT” 部分懒得数了,先凑合看一下
题解
chiking 的偶像
大致题意
循环输出 \soup_god/,且总共输出的字符串长度为 n n n
思路
简单的签到题,只需要还记得有 mod 这个运算就能写出来
AC Code
#include "bits/stdc++.h"
using namespace std;
void solve() {
const char *data = "\\soup_god/";
int n;
cin >> n;
for (int i = 0; i < n; ++i) {
cout << data[i % 10];
}
cout << endl;
}
chiking 和珂朵莉
大致题意
n n n 个物品,每个物品都有价值和所属类别,让你选择 n − k n - k n−k 种类别的物品,使得所选出来的这些类别的物品的总价值最大
思路
也是签到题之一
在读入数据的时候统计每个类别的物品价值只和,之后排序一下,取出后 n − k n - k n−k 个类别的价值即可
AC Code
#include "bits/stdc++.h"
using namespace std;
void solve() {
int w[11] = {
0};
int m, n, k;
cin >> m >> n >> k;
for (int i = 0; i < m; ++i) {
int d, s;
cin >> d >> s;
w[s] += d;
}
sort(w + 1, w + n + 1);
int ans = 0;
for (int i = k + 1; i <= n; ++i) ans += w[i];
cout << ans << endl;
}
吐槽
这道题原来有一个小坑点,即物品的价值可以为负数,所以需要额外增加一个判断,但是想了想还是当签到题,不要故意恶心了,于是就删掉了。所以顺便好奇的问一下,有多少人看到题面之后去想过价值是不是可能为负数呢
chiking 的序列 II
大致题意
有一个非递减的数组,允许你进行任意次数操作,每次操作可以使得其中一个值增加 1 1 1,问至少需要多少次操作才能使得数组内没有相同的值
思路
因为只能进行加法运算,所以数字只会增加,由于已经排序好了数组,所以最简单的方案就是让每一个值都比前一个值要大即可
AC Code
#include "bits/stdc++.h"
using namespace std;
void solve() {
int n;
cin >> n;
vector<int> data(n);
for (int i = 0; i < n; ++i) cin >> data[i];
long long sum = 0;
for (int i = 1; i < n; ++i) {
int tmp = max(data[i - 1] + 1, data[i]);
sum += tmp - data[i];
data[i] = tmp;
}
cout << sum << endl;
}
chiking 的序列 I
大致题意
有一个数组,允许你进行任意次操作,每次执行操作可以将任意一个数字插入到数组到任意位置,问至少需要多少次操作才能使得数组内到每一个值满足 a i ≤ i a_i \leq i ai≤i,其中 i i i 表示下标
思路
首先要让每一位的的数字小于等于其下标,那么插入的数字也不能例外。由于插入的数字可以是任意值,所以理所应当的,选择 1 1 1 进行插入是最好的选择,因为无论插入何处均可以使得新插入的数字不再需要考虑
接下来是考虑插入位置的问题,在等式中 a i a_i ai 是不可更新的值,所以只能想办法使得 i i i 增大,那么最容易得到的解决方案就是将数字插入数组开头,这会使得所有原来在数组内的值的下标都增大,最大程度的满足条件
接下来考虑插入数量的问题,由于都是插入数组最前面,所以可以将等式改写为 a i < = i + x a_i <= i + x ai<=i+x,其中的 x x x 即为需要求解的值。那么对于每一个 i i i 都要满足这个等式,所以遍历一次数组,找出最大的需要的 x x x 即可
AC Code
#include "bits/stdc++.h"
using namespace std;
void solve() {
int _;
cin >> _;
for (int ts = 0; ts < _; ++ts) {
int n;
cin >> n;
int ans = 0;
for (int i = 0; i < n; ++i) {
int tmp;
cin >> tmp;
ans = max(ans, tmp - i - 1);
}
cout << ans << endl;
}
}
chiking 的棋盘
大致题意
用 k k k 个 L 形状的方块能否平铺一个矩形方格
思路
我们可以用 L 形状的方块拼出如下两种最简平铺方案
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JhYBmf9b-1639041859538)(/image/acm/2021-ZJGSU-ACM-freshman-competition/2*4.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q0HQwnc4-1639041859539)(/image/acm/2021-ZJGSU-ACM-freshman-competition/3*8.png)]
这两个方案都是 8 8 8 个方格的倍数,所以起码,方格总数应该是 8 8 8 的倍数,即 n × m = 8 k n \times m = 8k n×m=8k
- 假设两边都是偶数,那么必然其中一边为 2 2 2 的倍数,另外一边为 4 4 4 的倍数,所以必然可以被仅靠第一种平铺方案平铺
- 假设一边为奇数一边是偶数,那么必然其中一边为 8 8 8 的倍数,而第一种方案也可以改写为 2 ∗ 8 2 * 8 2∗8 的方格,即只需要另外一边可以分解为 2 x + 3 y 2x + 3y 2x+3y 的形式即可,易得只要 $ \geq 2$ 的值均可
所以结论:只要满足方格数为 8 8 8 的倍数,且两边都 $ \geq 2$,则必定可以平铺
接下来只需要计算数量对不对就行
AC Code
#include "bits/stdc++.h"
using namespace std;
void solve() {
#define int long long
int _;
cin >> _;
for (int ts = 0; ts < _; ++ts) {
int n, m, k;
cin >> n >> m >> k;
if (n > 1 && m > 1 && (n * m) % 8 == 0) {
int cnt = (n * m / 4);
if (cnt == k) cout << "Perfect!\n";
else cout << "Single forever!\n";
} else cout << "Single forever!\n";
}
}
乐于助人的 chiking
大致题意
允许将字符串中 oo 和 u 互转,也允许将字符串的 kh 和 h 互转的前提下,计算给出的字符串数组中有几个不同的字符串
思路
由于存在转换,所以最好的办法就是统一转为一种类型,再进行比较
oo 和 u 这对规则,若我们将所有的 oo 转为 u,那么当遇到 ou 和 uo 时,会发现在此条规则下应该是相等的字符串没有相等。所以应该将所有的 u 字符转为 oo
kh 和 h 这对规则,若我们将所有的 h 转为 kh,那么就会出现 kh 还可以继续转为 kkh、kkkh、kkkkh 等,所以只能选择将 kh 转为 h。但是请注意 kkkh 这类连续的 k 的情况,可以连续多次转换
处理完成后,统计不同的字符串的数量即可
处理字符串复杂度 O ( n m ) = 1 e 5 O(nm) = 1e5 O(nm)=1e5
统计不同字符串数量 O ( n 2 m ) = 1 e 7 O(n^2m) = 1e7 O(n2m)=1e7
满足要求
AC Code
#include "bits/stdc++.h"
using namespace std;
char a[1010], b[2010];
void solve() {
int n;
cin >> n;
vector<string> data;
for (int i = 0; i < n; ++i) {
cin >> a;
int len = (int) strlen(a);
int pos = 0;
for (int j = 0; j < len; ++j) {
if (a[j] == 'u') {
b[pos++] = 'o';
b[pos++] = 'o';
} else if (a[j] == 'h') {
while (pos > 0 && b[pos - 1] == 'k') pos--;
b[pos++] = 'h';
} else {
b[pos++] = a[j];
}
b[pos] = 0;
}
data.emplace_back(b);
}
int cnt = 0;
for (int i = 0; i < n - 1; ++i) {
bool flag = true;
for (int j = i + 1; j < n; ++j) {
if (data[i] == data[j]) {
flag = false;
break;
}
}
if (flag) cnt++;
}
cout << cnt + 1 << endl;
}
更好的优化
实际上,这里需要比较的是字符串是否相同,所以可以使用字符串 hash 来解决,这样,复杂度将会降低至 O ( n m ) O(nm)


6748

被折叠的 条评论
为什么被折叠?



