七夕了呀,那就刷题吧~~~
本次试题依旧使用 C++ 进行求解~由于疫情原因,本次PAT由原来的线下举办改为线上考试9月份还有一场,想参加的小伙伴不要错过呀
由于本人过菜,这次七夕教超打折依旧只敢去做做乙级题(截至目前已售出30份)~😂
废话不多说,开冲!
PAT(乙级)2020年春季考试直达链接:这里
试题集の基本情况
对称日(15分)
思路
- 需要处理输入的 date
- 将月份应为简写转换为对应的数字
- 将年日月按要求组合起来
- 检验是否为对称日
- 可以转换为字符串,按对应的位或者反转进行对比
- 可以将月份与日期的和(月份 * 100 + 日期)反转,与年份对比
这里我使用了 map 作为月份(英文 - 数字)的映射、 sprintf 格式化字符串接着按位比较~ 太香啦~~(由于太菜,使用其他方法补零补到崩溃,导致做了半个小时才AC的屑博主)
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <string>
using std::string;
using std::unordered_map;
int main() {
unordered_map<string, int> um{
{"Jan", 1},
{"Feb", 2},
{"Mar", 3},
{"Apr", 4},
{"May", 5},
{"Jun", 6},
{"Jul", 7},
{"Aug", 8},
{"Sep", 9},
{"Oct", 10},
{"Nov", 11},
{"Dec", 12}
};
int cnt{ 0 }, year{ 0 }, day{ 0 };
char month[5];
scanf("%d", &cnt);
getchar();
for (int i = 0; i < cnt; i++) {
scanf("%s %d, %d", month, &day, &year);
char date[10];
sprintf(date, "%04d%02d%02d", year, um[string(month)], day);
int left = 0, right = 7;
while (left < right) {
if (date[left] != date[right]) {
putchar('N');
break;
}
left++;
right--;
}
if (left > right) {
putchar('Y');
}
printf(" %04d%02d%02d\n", year, um[string(month)], day);
}
return 0;
}
结论
模拟题。细心 + 技巧 + 规范输出 = AC
超标区间(20分)
思路
害,看到这种题不要怕,只要它不搞什么奇奇怪怪的要求就直接莽!!!
题目要求按顺序输出超过 limit 的区间,那我们就可以使用两个变量 —— left、right 作为区间的边界范围
每次输出了之后记得将它们重新设为“未使用状态”,这个未使用状态具体是指什么,看代码你就知道啦
代码
#include <cstdio>
int main() {
int cnt{ 0 }, limit{ 0 }, num{ 0 }, max{ -1 };
bool flag{ false };
scanf("%d %d", &cnt, &limit);
int left{ -1 }, right{ -1 };
for (int i = 0; i < cnt; i++) {
scanf("%d", &num);
if (num > max) {
max = num;
}
if (num > limit) {
if (left != -1) {
right++;
} else {
left = i;
right = i;
}
} else {
if (right != -1) {
flag = true;
printf("[%d, %d]\n", left, right);
left = -1;
right = -1;
}
}
}
if (right != -1) {
printf("[%d, %d]\n", left, right);
} else if (!flag) {
printf("%d\n", max);
}
return 0;
}
结论
模拟题。细心 + 想办法去模拟 + 正确处理边界条件 = AC
钱串子的加法(20分)
思路
这道题看着很唬人,想着陈越姥姥在PTA之前还在说今年线上考试,出题要避免模板题......
哦豁,这不就是模板题嘛!字符串加法 + 一丢丢的字符处理
模板请戳 :这里!
评论区第一个就是了~~~ 光速AC😂
代码
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
using std::cin;
using std::cout;
using std::endl;
using std::string;
void addition(string& a, string& b) {
int carry = 0;
int index_a = static_cast<int>(a.length()) - 1;
int index_b = static_cast<int>(b.length()) - 1;
string ans;
while (index_a >= 0 || index_b >= 0 || carry != 0) {
if (index_a >= 0) {
if (isalpha(a[index_a])) {
carry += a[index_a] - 'a' + 10;
} else {
carry += a[index_a] - '0';
}
index_a--;
}
if (index_b >= 0) {
if (isalpha(b[index_b])) {
carry += b[index_b] - 'a' + 10;
} else {
carry += b[index_b] - '0';
}
index_b--;
}
if (carry % 30 >= 10) {
ans.push_back('a' - 10 + carry % 30);
} else {
ans.push_back('0' + carry % 30);
}
carry /= 30;
}
int index = static_cast<int>(ans.length()) - 1;
while (ans.size() > 1 && ans[index] == '0') {
ans.pop_back();
index--;
}
std::reverse(ans.begin(), ans.end());
printf("%s\n", ans.c_str());
}
int main() {
string a, b;
cin >> a >> b;
addition(a, b);
return 0;
}
结论
有些时候遇到经典的题,背背模板也没什么嘛~~
那都是前人的智慧呀!这里的“背”不是“死背”哦,不然是会很容易忘的!
这道题有个坑点 :如果你的第三个测试点错了,那你可来对地方了!
这道题要求我们去除前导 0,而大家的处理方法大多都一心放在去除 0 上面而忽略掉了这个情况 —— 相加的两个数都是 0 时,结果为 0 ,这个 0 不能去掉~
我敢保证测试点3的数据就是 —— 0 0 ,故意坑你们🤣
全素日(20分)
思路
一开始看到这道题时,想着一位数、两位数、三位数这样一步步递增上去检查。But 题目要求是要按照 twitter 样式输出的,好吧~~
继续暴力模拟就完事,完全用不着什么素数线性筛,直接暴力 sqrt 即可~~
代码
#include <cstdio>
#include <string>
#include <cmath>
using std::string;
bool isPrime(int num) {
if (num < 2) {
return false;
}
for (int i = 2; i <= static_cast<int>(sqrt(num)); i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
void judge(int num) {
char date[10];
sprintf(date, "%08d", num);
string str{ date };
bool all{ true };
for (int i = 0; i < str.length(); i++) {
string temp = str.substr(i);
bool flag = isPrime(stoi(temp));
if (!flag) {
all = false;
}
printf("%s %s\n", temp.c_str(), flag ? "Yes" : "No");
}
if (all) {
puts("All Prime!");
}
}
int main() {
int num{ 0 };
scanf("%d", &num);
judge(num);
return 0;
}
结论
如果你是测试点2、5答案错误而来的,那你没有白来~
提供测试点 :00010101
哈哈,发现问题所在了吧,这种奇奇怪怪的边界条件就是卡你的测试点(sprintf 永远的神!)~
处理好他们就可以 AC 啦!
裁判机(25分)
思路
可可爱爱没有脑袋~~ 又到了最后的 25 分题了,有点小紧张~(* ̄3 ̄)╭
其实很简单啦,只是这个通过率有点让人害怕而已🤗
这题需要用到工具人 —— unordered_set 和 vector ,如果小伙伴没有见过这个玩意儿,不用慌~
指路👉 tools
学成归来还请赏个赞呐~~~
简单来说就是把初始的两个数加到 set 里,然后根据回合依次判断 player 的数字是否合法。具体做法就是看他说的数加上 set 中的某个数是否存在与 set 中,如果存在,则合法,把他说的数加进set。否则淘汰,这里有个需要注意的点就是,如果某人在第 n 轮淘汰了,那么后面的 n + m (m > 0)轮都可以跳过他了~~~
废话不多说,直接开冲!
代码
#include <cstdio>
#include <unordered_set>
#include <vector>
using std::vector;
using std::unordered_set;
int main() {
int fst{ 0 }, sec{ 0 };
int row{ 0 }, col{ 0 };
scanf("%d %d", &fst, &sec);
scanf("%d %d", &row, &col);
vector<vector<int>> v(row, vector<int>(col));
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
scanf("%d", &v[i][j]);
}
}
vector<bool> player(row, true);
unordered_set<int> us{ fst, sec };
for (int i = 0; i < col; i++) {
for (int j = 0; j < row; j++) {
if (!player[j]) {
continue;
}
if (us.count(v[j][i])) {
printf("Round #%d: %d is out.\n", i + 1, j + 1);
player[j] = false;
} else {
bool valid{ false };
for (auto& x : us) {
if (us.count(x + v[j][i])) {
valid = true;
us.insert(v[j][i]);
break;
}
}
if (!valid) {
printf("Round #%d: %d is out.\n", i + 1, j + 1);
player[j] = false;
}
}
}
}
bool flag{ false };
for (int i = 0; i < row; i++) {
if (player[i]) {
if (!flag) {
printf("Winner(s):");
flag = true;
}
printf(" %d", i + 1);
}
}
if (!flag) {
puts("No winner.");
}
return 0;
}
结论
STL 真香!你知道吗,乙级题最后一题就喜欢考STL的使用哦~~
总结
做了这几年的乙级题,感觉风格越来越收敛了,这次的乙级试题做下来,整体感觉难度和19年冬难度差不多~~
这次的试题难度放在乙级题库里的话,难度算是中等偏易了(没有今年的520钻石争霸赛难)
如果你是备考乙级的小伙伴,那么我推荐你去多做做乙级题库中通过率比较高的题,STL 题和排序题也要去做,做到烂熟于心。
同时可以去LeetCode逛逛哟,做做简单的题目~~对于编码的基础水平也有很大的提升哦!
乙级虽然报考的人数远远小于甲级(甲级永远的神),但也还是指的一试的。这也算是对自己能力的肯定,而且乙级满分也能收到offer哦!
总之,乙级 = 熟练模拟题 + STL + 边界处理 + 细心 + 一些基础数据结构的理解(链表、栈、队列等等,没有树和图,它们都在隔壁甲级~~全学总不会错哈😜)