2020年11月团体程序设计天梯赛
第一次参加天梯赛,除了在门口冻得瑟瑟发抖,还有按不动的shift之外一切都还好…
tip:不知道啥原因代码上基本没有注释,希望dalao们不要介意~
L1-1 嫑废话上代码 (5分)
Linux 之父 Linus Torvalds 的名言是:“Talk is cheap. Show me the code.”(嫑废话,上代码)。本题就请你直接在屏幕上输出这句话。
输入格式:
本题没有输入。
输出格式:
在一行中输出 Talk is cheap. Show me the code.
。
输入样例:
无
输出样例:
Talk is cheap. Show me the code.
思路:
送“命”题,这岂不是“有手就行”?
上代码 :
#include <bits/stdc++.h>
using namespace std;
int main()
{
cout<<"Talk is cheap. Show me the code.";
return 0;
}
L1-2 猫是液体 (5分)
测量一个人的体积是很难的,但猫就不一样了。因为猫是液体,所以可以很容易地通过测量一个长方体容器的容积来得到容器里猫的体积。本题就请你完成这个计算。
输入格式:
输入在第一行中给出 3 个不超过 100 的正整数,分别对应容器的长、宽、高。
输出格式:
在一行中输出猫的体积。
输入样例:
23 15 20
输出样例:
6900
思路:
同样是一道送分题,如果你从题目中读不出来这是一道简单的求长方体的体积的数学题,那么建议你去多学学语文。
上代码 :
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x, y, z;
cin >> x >> y >> z;
cout << x * y * z;
return 0;
}
L1-3 洛希极限 (10分)
科幻电影《流浪地球》中一个重要的情节是地球距离木星太近时,大气开始被木星吸走,而随着不断接近地木“刚体洛希极限”,地球面临被彻底撕碎的危险。但实际上,这个计算是错误的。
洛希极限(Roche limit)是一个天体自身的引力与第二个天体造成的潮汐力相等时的距离。当两个天体的距离少于洛希极限,天体就会倾向碎散,继而成为第二个天体的环。它以首位计算这个极限的人爱德华·洛希命名。(摘自百度百科)
大天体密度与小天体的密度的比值开 3 次方后,再乘以大天体的半径以及一个倍数(流体对应的倍数是 2.455,刚体对应的倍数是 1.26),就是洛希极限的值。例如木星与地球的密度比值开 3 次方是 0.622,如果假设地球是流体,那么洛希极限就是 0.622×2.455=1.52701 倍木星半径;但地球是刚体,对应的洛希极限是 0.622×1.26=0.78372 倍木星半径,这个距离比木星半径小,即只有当地球位于木星内部的时候才会被撕碎,换言之,就是地球不可能被撕碎。
本题就请你判断一个小天体会不会被一个大天体撕碎。
输入格式:
输入在一行中给出 3 个数字,依次为:大天体密度与小天体的密度的比值开 3 次方后计算出的值(≤1)、小天体的属性(0 表示流体、1 表示刚体)、两个天体的距离与大天体半径的比值(>1 但不超过 10)。
输出格式:
在一行中首先输出小天体的洛希极限与大天体半径的比值(输出小数点后2位);随后空一格;最后输出 ^_^
如果小天体不会被撕碎,否则输出 T_T
。
输入样例 1:
0.622 0 1.4
输出样例 1:
1.53 T_T
输入样例 2:
0.622 1 1.4
输出样例 2:
0.78 ^_^
思路:
题目一大坨,实际有用的信息无非就两条 两个天体的距离少于洛希极限,天体就会倾向碎散
,流体对应的倍数是 2.455,刚体对应的倍数是 1.26
,只需计算一下洛希极限,然后比较洛希极限和距离就好了。
上代码 :
#include <bits/stdc++.h>
using namespace std;
int main()
{
double s, t[2] = {2.455, 1.26}, c;
int f;
cin >> s >> f >> c;
cout << fixed << setprecision(2) << s * t[f] << (s * t[f] > c ? " T_T" : " ^_^");
return 0;
}
L1-4 调和平均 (10分)
N 个正数的算数平均是这些数的和除以 N,它们的调和平均是它们倒数的算数平均的倒数。本题就请你计算给定的一系列正数的调和平均值。
输入格式:
每个输入包含 1 个测试用例。每个测试用例第 1 行给出正整数 N (≤1000);第 2 行给出 N 个正数,都在区间 [0.1,100] 内。
输出格式:
在一行中输出给定数列的调和平均值,输出小数点后2位。
输入样例:
8
10 15 12.7 0.3 4 13 1 15.6
输出样例:
1.61
思路:
一个数的倒数是以它为分母分之一,即1除以这个数,这些数的倒数的算数平均为sum/n,调和平均是它们倒数的算数平均的倒数也就是n/sum,如果能理解到这一点,这个题也就可以轻而易举的ac啦~
上代码 :
#include <bits/stdc++.h>
using namespace std;
int main()
{
double sum = 0;
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
double a;
cin >> a;
sum += 1 / a;
}
cout << fixed << setprecision(2) << n / sum;
return 0;
}
L1-5 胎压监测 (15分)
小轿车中有一个系统随时监测四个车轮的胎压,如果四轮胎压不是很平衡,则可能对行车造成严重的影响。
让我们把四个车轮 —— 左前轮、右前轮、右后轮、左后轮 —— 顺次编号为 1、2、3、4。本题就请你编写一个监测程序,随时监测四轮的胎压,并给出正确的报警信息。报警规则如下:
- 如果所有轮胎的压力值与它们中的最大值误差在一个给定阈值内,并且都不低于系统设定的最低报警胎压,则说明情况正常,不报警;
- 如果存在一个轮胎的压力值与它们中的最大值误差超过了阈值,或者低于系统设定的最低报警胎压,则不仅要报警,而且要给出可能漏气的轮胎的准确位置;
- 如果存在两个或两个以上轮胎的压力值与它们中的最大值误差超过了阈值,或者低于系统设定的最低报警胎压,则报警要求检查所有轮胎。
输入格式:
输入在一行中给出 6 个 [0, 400] 范围内的整数,依次为 1~4 号轮胎的胎压、最低报警胎压、以及胎压差的阈值。
输出格式:
根据输入的胎压值给出对应信息:
- 如果不用报警,输出
Normal
; - 如果有一个轮胎需要报警,输出
Warning: please check #X!
,其中X
是出问题的轮胎的编号; - 如果需要检查所有轮胎,输出
Warning: please check all the tires!
。
输入样例 1:
242 251 231 248 230 20
输出样例 1:
Normal
输入样例 2:
242 251 232 248 230 10
输出样例 2:
Warning: please check #3!
输入样例 3:
240 251 232 248 240 10
输出样例 3:
Warning: please check all the tires!
思路:
只要这个轮胎的胎压与最大值的差超过阈值或者比最小值小,就记录为不合格轮胎,最后再根据不合格轮胎的数量输出相应的内容。
上代码 :
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a[5], x, y, maxn = -1;
for (int i = 1; i <= 4; i++)
{
cin >> a[i];
maxn = max(maxn, a[i]);
}
cin >> x >> y;
vector<int> ans;
for (int i = 1; i <= 4; i++)
{
if (maxn - a[i] > y || a[i] < x)
{
ans.push_back(i);
}
}
if (ans.size() == 1)
{
cout << "Warning: please check #" << ans[0] << "!";
}
else if (ans.size() == 0)
{
cout << "Normal";
}
else
{
cout << "Warning: please check all the tires!";
}
return 0;
}
L1-6 吃火锅 (15分)
以上图片来自微信朋友圈:这种天气你有什么破事打电话给我基本没用。但是如果你说“吃火锅”,那就厉害了,我们的故事就开始了。
本题要求你实现一个程序,自动检查你朋友给你发来的信息里有没有 chi1 huo3 guo1
。
输入格式:
输入每行给出一句不超过 80 个字符的、以回车结尾的朋友信息,信息为非空字符串,仅包括字母、数字、空格、可见的半角标点符号。当读到某一行只有一个英文句点 .
时,输入结束,此行不算在朋友信息里。
输出格式:
首先在一行中输出朋友信息的总条数。然后对朋友的每一行信息,检查其中是否包含 chi1 huo3 guo1
,并且统计这样厉害的信息有多少条。在第二行中首先输出第一次出现 chi1 huo3 guo1
的信息是第几条(从 1 开始计数),然后输出这类信息的总条数,其间以一个空格分隔。题目保证输出的所有数字不超过 100。
如果朋友从头到尾都没提 chi1 huo3 guo1
这个关键词,则在第二行输出一个表情 -_-#
。
输入样例 1:
Hello!
are you there?
wantta chi1 huo3 guo1?
that's so li hai le
our story begins from chi1 huo3 guo1 le
.
输出样例 1:
5
3 2
输入样例 2:
Hello!
are you there?
wantta qi huo3 guo1 chi1huo3guo1?
that's so li hai le
our story begins from ci1 huo4 guo2 le
.
输出样例 2:
5
-_-#
思路:
依此遍历字符串,只要出现“chi1 huo3 guo1”,如果是第一次就记录他的位置,记录次数,要注意可能会出现 “Achi1 huo3 guo1”(其中A为任意字母),所以需要特判一下,A的位置是否为空格,或者’c’就是s[0]的位置。
当然你如果知道了find函数,那么这个题目解决起来将会出奇的简单~
上代码 :
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s;
int ft = 0, ans = 0, c = 0;
while (1)
{
getline(cin, s);
if (s == ".")
break;
c++;
if (s.length() < 14)
continue;
for (int i = 0; i < s.length() - 13; i++)
{
if (s.substr(i, 14) == "chi1 huo3 guo1" && (i == 0 || s[i - 1] == ' '))
{
ans++;
if (!ft)
ft = c;
}
}
}
cout << c << endl;
if (ft)
{
cout << ft << " " << ans;
}
else
{
cout << "-_-#";
}
return 0;
}
解法2:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
string s;
int cnt = 0;
vector<int> v;
while (getline(cin, s) && s != ".")
{
cnt++;
int pos = s.find("chi1 huo3 guo1", 0);
if (pos != -1)
v.push_back(cnt);
}
cout << cnt << endl;
if (v.empty())
cout << "-_-#";
else
{
cout << v[0] << " " << v.size();
}
return 0;
}
L1-7 前世档案 (20分)
网络世界中时常会遇到这类滑稽的算命小程序,实现原理很简单,随便设计几个问题,根据玩家对每个问题的回答选择一条判断树中的路径(如下图所示),结论就是路径终点对应的那个结点。
现在我们把结论从左到右顺序编号,编号从 1 开始。这里假设回答都是简单的“是”或“否”,又假设回答“是”对应向左的路径,回答“否”对应向右的路径。给定玩家的一系列回答,请你返回其得到的结论的编号。
输入格式:
输入第一行给出两个正整数:N(≤30)为玩家做一次测试要回答的问题数量;M(≤100)为玩家人数。
随后 M 行,每行顺次给出玩家的 N 个回答。这里用 y
代表“是”,用 n
代表“否”。
输出格式:
对每个玩家,在一行中输出其对应的结论的编号。
输入样例:
3 4
yny
nyy
nyn
yyn
输出样例:
3
5
6
2
思路:
仔细看看图的话,不难看出这其实就是一个二进制(n代表1,y代表0)然后再加一,例如:nyy就相当于二进制100+1=101 二进制的101就是5。
或者你如果回bitset(二进制类)的话,也可以看解法2。
上代码 :
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x, y;
cin >> x >> y;
while (y--)
{
string s;
cin >> s;
reverse(s.begin(), s.end());
int ans = 1;
for (int i = 0; i < s.length(); i++)
{
if (s[i] == 'n')
ans += pow(2, i);
}
cout << ans << endl;
}
return 0;
}
解法2:
#include <iostream>
#include <bitset>
using namespace std;
int main()
{
int n, m;
cin >> n >> m;
while (m--)
{
string s;
cin >> s;
for (auto &c : s)
{
if (c == 'y')
c = '0';
else
c = '1';
}
bitset<30> v(s);
cout << v.to_ulong()+1 << endl;
}
return 0;
}
L1-8 刮刮彩票 (20分)
“刮刮彩票”是一款网络游戏里面的一个小游戏。如图所示:
每次游戏玩家会拿到一张彩票,上面会有 9 个数字,分别为数字 1 到数字 9,数字各不重复,并以 3×3 的“九宫格”形式排布在彩票上。
在游戏开始时能看见一个位置上的数字,其他位置上的数字均不可见。你可以选择三个位置的数字刮开,这样玩家就能看见四个位置上的数字了。最后玩家再从 3 横、3 竖、2 斜共 8 个方向中挑选一个方向,方向上三个数字的和可根据下列表格进行兑奖,获得对应数额的金币。
数字合计 | 获得金币 | 数字合计 | 获得金币 |
---|---|---|---|
6 | 10,000 | 16 | 72 |
7 | 36 | 17 | 180 |
8 | 720 | 18 | 119 |
9 | 360 | 19 | 36 |
10 | 80 | 20 | 306 |
11 | 252 | 21 | 1,080 |
12 | 108 | 22 | 144 |
13 | 72 | 23 | 1,800 |
14 | 54 | 24 | 3,600 |
15 | 180 |
现在请你写出一个模拟程序,模拟玩家的游戏过程。
输入格式:
输入第一部分给出一张合法的彩票,即用 3 行 3 列给出 0 至 9 的数字。0 表示的是这个位置上的数字初始时就能看见了,而不是彩票上的数字为 0。
第二部给出玩家刮开的三个位置,分为三行,每行按格式 x y
给出玩家刮开的位置的行号和列号(题目中定义左上角的位置为第 1 行、第 1 列。)。数据保证玩家不会重复刮开已刮开的数字。
最后一部分给出玩家选择的方向,即一个整数: 1 至 3 表示选择横向的第一行、第二行、第三行,4 至 6 表示纵向的第一列、第二列、第三列,7、8分别表示左上到右下的主对角线和右上到左下的副对角线。
输出格式:
对于每一个刮开的操作,在一行中输出玩家能看到的数字。最后对于选择的方向,在一行中输出玩家获得的金币数量。
输入样例:
1 2 3
4 5 6
7 8 0
1 1
2 2
2 3
7
输出样例:
1
5
6
180
思路:
一道“复杂”的过程模拟题,只要完全“被题目牵着鼻子走”,感觉就没有不ac的理由了。
上代码 :
#include <bits/stdc++.h>
using namespace std;
int main()
{ // 记录对应奖金的数组
int a[4][4], t[25] = {0, 0, 0, 0, 0, 0, 10000, 36, 720, 360, 80, 252, 108, 72, 54, 180, 72, 180, 119, 36, 306, 1080, 144, 1800, 3600};
pair<int, int> p;
set<int> check;
for (int i = 1; i < 4; i++)
{
for (int j = 1; j < 4; j++)
{
cin >> a[i][j];
check.insert(a[i][j]); //用来查找最后哪个元素被0替代了
if (a[i][j] == 0)
{
p.first = i, p.second = j; //记录下0的位置
}
}
}
for (int i = 1; i < 10; i++)
{
if (check.count(i) == 0)
{
a[p.first][p.second] = i; //把0覆盖掉的值还回去
break;
}
}
for (int i = 1; i < 4; i++)
{
cin >> p.first >> p.second;
cout << a[p.first][p.second] << endl;
}
int k, ans = 0;
cin >> k;
if (k <= 3)
{
for (int i = 1; i < 4; i++)
{
ans += a[k][i];
}
}
else if (k <= 6)
{
for (int i = 1; i < 4; i++)
{
ans += a[i][k - 3];
}
}
else if (k == 7)
{
for (int i = 1; i < 4; i++)
{
ans += a[i][i];
}
}
else
{
for (int i = 1; i < 4; i++)
{
ans += a[i][4 - i];
}
}
cout << t[ans];
return 0;
}
总结
没想到在比赛的时候能把这100分给AK了,而且也是最后在吃火锅的地方拿到最后4分压线拿到个人银奖,赛后写这篇题解的时候只能用三个字来形容,就是“困困困”,所以中途睡了会,历时4个半小时,下班!
顺便定个小目标,我一定要“玩转二叉树”