admin管理员组

文章数量:815314

[PTA]2021天梯赛

文章目录

    • 前言说明
    • 题解
      • 人与神 (5 分)
      • 两小时学完C语言 (5 分)
      • 强迫症 (10 分)
      • 降价提醒机器人 (10 分)
      • 大笨钟的心情 (15 分)
      • 吉老师的回归 (15 分)
      • 天梯赛的善良 (20 分)
      • 乘法口诀数列 (20 分)
    • 总结

前言说明

题集连接: 团体程序设计天梯赛-练习集

L1的题号从L1-73到L-80

代码可以无限提交,当场出分。比ACM赛制好很多。

虽说是团队赛,但这个团队指的是最后团队所有人的分数总和,现场还是个人编程做题。不是像ACM一样三人一队的形式。且最后还会评个人总分。就是说你可以难道两张证。

L1的题目总分100分,一队10人。只有团队总分到达800分时,才能进入L2部分。(L2可写,但不满800不计入团队总分,但能计入个人总分)

题解

以下代码全部通过测试

人与神 (5 分)

人与神 (5 分)

解读

直接输出字符串To iterate is human, to recurse divine.即可。换不换行都能通过。

代码

#include <bits/stdc++.h>
using namespace std;int main (void)
{cout << "To iterate is human, to recurse divine." << endl;return 0;
}

小结

这题的难度就是直接打印Hello World的级别。

赛场上做本题最大的收获是,知道了不要刚开考就点进5分题!因为刚开考的时候全国的选手都在进入系统,会崩溃。建议进入后直接点个15,或20分左右题看看。不然在等系统恢复时候你就是在干等浪费时间!


两小时学完C语言 (5 分)

两小时学完C语言 (5 分)

解读

直接输入后输出n-k*m即可。

代码

#include <bits/stdc++.h>
using namespace std;int main (void)
{int n, k, m;cin >> n >> k >> m;cout << n-k*m << endl;return 0;
}

小结

由于本题只是一个5分题,k*m不会超出int范围,且题干里明确表明了看过的总字数不会超过n,所以就不用考虑n<0的情况。

但是这些细节是我们平时在做题的时候自己就该一下子联想到的。


强迫症 (10 分)

强迫症 (10 分)

解读

对于数字型的输入方法式,我们不但可以直接输入数字,还可以以字符串的方式输入。

分别根据串长为4或6进行处理。

最后输出可以直接输出一个串,也可以以三部分 年+“-”+月进行输出。

代码

#include <bits/stdc++.h>
using namespace std;int main (void)
{string s;cin >> s;int len = s.size();if (len == 6){  //输入6位s.insert(4, "-");}else{          //输入4位s.insert(2, "-");string nian = s.substr(0, 2);int num = stoi(nian);if (num < 22){s.insert(0, "20");}else{s.insert(0, "19");}}cout << s << endl;return 0;
}

此处对于串长为6的,直接在串中插入“-”即可。

对于串长为4的,还要先截取前两位的年份,进行判断,再把完整年份放入串中。

小结

s.insert(pos str); 在该串的pos位置后面插入str

s.substr(pos, len); 在该串的pos位置起,获取长度为len的字串

stoi(str); 将字符串转换成int 同理还有stod(double), stoll(long long)等等


降价提醒机器人 (10 分)

降价提醒机器人 (10 分)

解读

本质还是比较数值大小,还要注意小数的输出。

代码

#include <bits/stdc++.h>
using namespace std;int main (void)
{int n;double price;cin >> n >> price;double cmp_price;while(n--){cin >> cmp_price;if (price - cmp_price > 0){
//             printf("On Sale! %.1lf\n", cmp_price);cout << "On Sale! " << fixed << setprecision(1) << cmp_price << endl; }}return 0;
}

小结

两种小数的输出方式,显然第一种printf型的好用,cout型的太难记了

printf(“On Sale! %.1lf\n”, cmp_price);
cout << "On Sale! " << fixed << setprecision(1) << cmp_price << endl;

。。。当时场上我cout型不会拼,而cout用太多,printf型的转义符等参数忘了哪个跟哪个对应。慌的一比。。。

最后急中生智之下。通过利用cout是输出有效位这一特点解决

double a = 1.0; cout << a << endl; 输出的是1

double b = 1.1; cout << b << endl ; 输出的是1.1

然后我通过把数值是否是整数来判断输出。(惊险)

判断方法式很多,我用的ceil和floor,上下取整是否相同判断

double a = 1.1;

cout << ceil(a) << endl; 输出的是2

cout << floor(a) << endl; 输出的是1,效果等同(int)a;


大笨钟的心情 (15 分)

大笨钟的心情 (15 分)

解读

传统题目,大笨钟。本质就是给串数字,根据下标来进行访问。如果下标越界,则停止程序。

代码

#include <bits/stdc++.h>
using namespace std;inline bool check(int num){return num >= 0 && num <= 23;
}int main (void)
{int arr[24];for (int i = 0; i < 24; i++){cin >> arr[i];}int ask;
//     while(cin >> ask)while(scanf("%d", &ask) != EOF){if (!check(ask))    break;
//         string s = arr[ask] > 50 ? "Yes" : "No";
//         cout << arr[ask] << " " << s << endl;printf("%d %s\n", arr[ask], arr[ask] > 50 ? "Yes" : "No");}return 0;
}

小结

如果说上面那题还是在考输入规定组数的数据,那本题就是很明显的多组输入。顺便提下printf可以用三元表达式(cout不行)

多组输入

while(cin >> ask)
while(scanf("%d", &ask) != EOF)

取消输入CTRL+Z

printf+三元表达式

printf("%d %s\n", arr[ask], arr[ask] > 50 ? “Yes” : “No”);


吉老师的回归 (15 分)

吉老师的回归 (15 分)

解读

计数性题目,如果串中有qiandao 或者 easy那可以不用计数。

当m不够计数时,则当前串就是需要输出的串。

如果到最后m还可以继续计数,则输出Wo AK le

代码

#include <bits/stdc++.h>
using namespace std;int main (void)
{int n, m;//共n题,已做m题cin >> n >> m;getchar();string s;string ans = "Wo AK le";while(n--){getline(cin, s);if (s.find("easy") != -1 || s.find("qiandao") != -1)continue;else{if (m == 0){ans = s;break;}else{m--;}}}cout << ans << endl;return 0;
}

小结

本题在输入方面考察了在非串或字符输入中间要考虑会回车的问题。通常有两种对应方式用getchar()吃掉这个回车,或者刷新一下缓冲区,这个涉及到一定输入输出流的知识点,就算法而言不怎么熟悉,所以用getchar()比较多。

还有pta这里的c++好像不支持gets();的输入了

getline(cin, s); 带空格输入string

s.find(str); 返回的是找到str或者单个字符的首次出现位置,如果没找到则返回-1

还有一点注意,OJ平台只检测我们的输出结果,所以没有把该输入的都输入到我们的程序中,就终止程序也是可以的。


天梯赛的善良 (20 分)

天梯赛的善良 (20 分)

解读

给定n个数值。正整数 N(≤2×10^4)

要求输出最小值及个数,最大值及个数

代码

数组排序版

#include <bits/stdc++.h>
using namespace std;int main (void)
{int n;cin >> n;vector<int>arr(n);for (int i = 0; i < n; i++){cin >> arr[i];}sort(arr.begin(), arr.end());int minNum = 0;for (int i = 0; i < n && arr[i] == arr[0]; i++){minNum++;}cout << arr[0] << " " << minNum << endl;int maxNum = 0;for (int i = n-1; i >= 0 && arr[i] == arr[n-1]; i--){maxNum++;}cout << arr[n-1] << " " << maxNum << edl;return 0;
}

map版

#include <bits/stdc++.h>
using namespace std;int main (void)
{int n;cin >> n;map<int, int>mp;int num;while(n--){cin >> num;mp[num]++;}auto its = mp.begin();cout << its->first << " " << its->second << endl;// begin() 和 rbegin() 的类型不同auto ite = mp.rbegin();cout << ite->first << " " << ite->second << endl;return 0;
}

小结

这题确实太善良了,我他跟没怎么读懂题,或说怎么读题。直接看输入输出的格式样例,就把题目AC了。

当时提交时候还以为会有什么细节在题干中。。。没想到过几秒告诉我AC了。。。

在排序版中,注意sort是默认从小打大,且最后在计数时加一个判断可以避免遍历完整个数组

在map版中,注意end()是最后一个元素的后一个位置,所以要往前退一个位置才能访问最后的元素。

顺便提一下,当容器元素为0时 begin() == end() 但本题明确是正整数就不用担忧这点了。


乘法口诀数列 (20 分)

乘法口诀数列 (20 分)

解读

其实样例说的很清除

2 3 10

2 3 6 1 8 6 8 4 8 4

数列前 2 项为 2 和 3。从 2 开始,因为 2×3=6,所以第 3 项是 6。因为 3×6=18,所以第 4、5 项分别是 1、8。依次类推…… 最后因为第 6 项有 6×8=48,对应第 10、11 项应该是 4、8。而因为只要求输出前 10 项,所以在输出 4 后结束。

乍一看还是处理数值的题目,再想一下各个步骤,分解乘出的数字,再计数,再用 双指针每次一个单位的移动计算。其实也不难,但是烦。

怎么化简操作呢?我们注意到一点,就是每项是一个个位数!那正好可以用字符串来处理。每个字符就是一个“数”。

string有丰富的库函数可以使用,这里使用的是C++11的新增的to_string可以将数值转化成string。然后不断连接串,再判断串长<n即可

代码

#include <bits/stdc++.h>
using namespace std;int main (void)
{int a1, a2, n;cin >> a1 >> a2 >> n;string s;s += to_string(a1);s += to_string(a2);for (int left = 0, right = 1; s.size() < n; left++, right++){int num_tmp = (s[left]-'0')*(s[right]-'0');s += to_string(num_tmp);}for (int i = 0; i < n; i++){cout << s[i];if (i+1 < n)    cout << " ";}return 0;
}

小结

赛场上直接读题后,没看样例解释,理解错了,浪费了好多时间。

最后还是用数值的处理方式写的,写的又臭又长,影响了一定的心态。。。

题目固然重要,但是样例解释更重要!

注意字符char本质是一个0~127的存储的数值

to_string(number); 将数值型转换成string

关于pta的输出 其实pta在最后是否是换行并不严格,但是对于最后输出一串数组的时候,通常要求最后一项后面没有宫格

这里给出四种常见处理方式

    //法一for (int i = 0; i < n; i++){cout << s[i];if (i+1 < n)    cout << " ";}//法二for (int i = 0; i < n; i++){if (i+1 < n)cout << s[i] << " ";elsecout << s[i];}//法三for (int i = 0; i < n-1; i++){cout << s[i] << " ";}cout << s[n-1] ;//法四for (int i = 0; i < n; i++){cout << s[i] << " \n"[i+1 == n];}

总结

天梯赛L1的题目总体还是很基础的,也会有分值的标明难度划分的比较明确。

到了现场比赛要有一定策略,比如不要一进入系统就点开看5分,10分的题,会很亏。如果进去了页面也直接崩了,那就把体面复制到编译器里。比赛规定不能打开txt,word之类得文档。

如果有部分题的个别测试样例没有过的话,不要太心急,先检查下有没有什么特殊条件没有考虑,特别是边界问题之类的。但如果死磕不出来也不要太钻牛角尖了。看看队友答得怎么样,只要全队分数满800就行了。

本文标签: PTA2021天梯赛