提前:本文中部分代码和思路有借鉴或摘抄计蒜客官方题解
赛后总结
本次模拟赛的难度总算正常了些 个人战绩: 220/400,排名61 ,太弱了,一大堆AK爷 题目质量评价: 题目相比CSP-J还是简单了一些,比较友好,题目质量还是比较高的。个人觉得前两题题面写的非常长,但是提炼出来重点后,就会觉得非常简单,很锻炼大家的信息提取与概括能力;代码实现难度低,平均也就个三四十行左右。 考查知识点: T1、2模拟,T3动态规划,T4堆 (没考图和树算法?)
题解
T1 鲜奶贩卖
题目链接: https://nanti.jisuanke.com/t/56597 涉及知识点: 模拟 解题思路: 签到题。 直接根据题意降价并判断即可。 正解代码:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int x, h, y;
bool f = false;
int main() {
freopen("milk.in", "r", stdin);
freopen("milk.out", "w", stdout);
cin >> x >> h >> y;
if (y >= x) {
f = true;
cout << 0 << endl;
} else {
for (int i = 1; i < h; i++) {
x -= ceil(1.0 * i / 10);
if (y >= x) {
f = true;
cout << i << endl;
return 0;
}
}
}
if (!f) {
cout << "IMPOSSIBLE" << endl;
}
return 0;
}
T2 滑冰游戏
题目链接: https://nanti.jisuanke.com/t/56598 涉及知识点: 模拟 解题思路: 相比T1,又增添了几分难度。 题面很长,概况一下:给定一个字符串为指定操作,可能向上、下、左、右移动,碰到'#' 代表的墙壁或者'.' 代表的冰块就停下。总分加上停下的这块方格的数值。也有可能打碎障碍冰块,冰块的方向一定是上一次操作的指定方向,且与人物相邻,打碎后原来冰块的地方分数为0 正解代码: 考场代码,可能有些冗杂,当然是可以优化的
#include <iostream>
#include <cstdio>
using namespace std;
int n, m, x, y;
long long ans;
string opr;
char map[25][25];
int main() {
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> map[i][j];
}
}
cin >> x >> y >> m >> opr;
for (int i = 0; i < m; i++) {
if (opr[i] == 'B') {
if (opr[i - 1] == 'U') map[x - 1][y] = '0';
if (opr[i - 1] == 'D') map[x + 1][y] = '0';
if (opr[i - 1] == 'L') map[x][y - 1] = '0';
if (opr[i - 1] == 'R') map[x][y + 1] = '0';
}
int mx = x, my = y;
if (opr[i] == 'U') {
while (map[mx - 1][my] != '*' && map[mx - 1][my] != '#') {
mx--;
}
ans += map[mx][my] - '0';
x = mx, y = my;
map[mx][my] = '0';
}
if (opr[i] == 'D') {
while (map[mx + 1][my] != '*' && map[mx + 1][my] != '#') {
mx++;
}
ans += map[mx][my] - '0';
x = mx, y = my;
map[mx][my] = '0';
}
if (opr[i] == 'L') {
while (map[mx][my - 1] != '*' && map[mx][my - 1] != '#') {
my--;
}
ans += map[mx][my] - '0';
x = mx, y = my;
map[mx][my] = '0';
}
if (opr[i] == 'R') {
while (map[mx][my + 1] != '*' && map[mx][my + 1] != '#') {
my++;
}
ans += map[mx][my] - '0';
x = mx, y = my;
map[mx][my] = '0';
}
}
cout << ans << endl;
return 0;
}
T3 小明与春娇叠积木
考试时这题竟然爆零了,丢脸 题目链接: https://nanti.jisuanke.com/t/56599 涉及知识点: 动态规划 解题思路: 分档考虑。 30pts: 这个子任务给了我们一个条件,那就是他们俩的积木是相同的,也就是说我们可以只操作一个。 第一种写法,是暴力枚举计算积木最高高度,这里就不多说了。 第二种写法,是动态规划,设dp[i] 是以i 结尾的最高高度核心部分给出:
for (int i = 1; i <= n; i++) {
dp[i] = 1;
for (int j = 1; j < i; j++) {
if (a[j] + 1 == a[i] && dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
}
}
if (dp[i] > ans) {
ans = dp[i];
}
}
60pts: 其实如果我们能够写出30pts的dp,我们就能照葫芦画瓢地对两座积木分别执行一样的dp操作。当然也可以用贪心做,我们设定i 是一个序列的起点,如果枚举中与a[j] 一样就把now/now2 加1,最后得出的就是
for (int i = 1; i <= n; i++) {
int now = i, now2 = i;
for (int j = 1; j <= n; j++) {
if (a[j] == now) {
now++;
}
if (b[j] == now2) {
now2++;
}
}
if (ans < min(now, now2) - i) {
ans = min(now, now2) - i;
}
}
100pts: 以动态规划的形式,计算两组积木的最高高度。 设dp[i] 为以i 结尾的最高高度,则状态转移方程为dp[i] = max(dp[i], dp[i - 1] + 1)
T4 苹果售卖
题目链接: https://nanti.jisuanke.com/t/56642 涉及知识点: 暴力即枚举、正解即堆 解题思路: 现在是2021年8月29日23:34分,我想睡觉了,明天再继续更新 正解代码: 明天写
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 2 * 1e5 + 5;
int n, ans;
int dp[2][MAXN];
void make_dp (int dp[], int n) {
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
dp[x] = max(dp[x], dp[x - 1] + 1);
}
return;
}
int main() {
freopen("juggle.in", "r", stdin);
freopen("juggle.out", "w", stdout);
cin >> n;
make_dp(dp[0], n);
make_dp(dp[1], n);
for (int i = 1; i <= n; i++) {
ans = max(ans, min(dp[0][i], dp[1][i]));
}
cout << ans << endl;
return 0;
}
反思
1.T1、2这种简单题尽量能15min内解决,也就是说基础算法我必须熟记于心,说写就写(达成) 2.对于动态规划和后面一堆奇奇怪怪的知识点本蒟蒻还在不断学习中,未来也是必须要熟练的,那么在2021CSP中我就要选择拿尽可能多的部分分 2021CSP-J++!
|