语法周赛round28
T1¶
本题考察顺序结构。
根据题意,每 $a$ 个瓶盖可以兑换 $5$ 元的现金券,而小 X 手上有 $n$ 个瓶盖。因此,可以兑换的现金券张数是 n / a,面值则是 n / a * 5。
例如说:$n=10,a=3$,小 X 有 $10$ 个瓶盖,每 $3$ 个瓶盖可以兑换一张 $5$ 元现金券,那么小 X 一共兑换 $3$ 张现金券,一共得到了 $15$ 元的现金券。
剩下的瓶盖数量就是 n % a。
T2¶
本题考察分支结构。
这道题问的是小 X 从睡觉到闹钟响了的时候睡了多久。为了方便处理,我们可以将时间 h1:m1:s1 化作这一天过去了 $t1$ 秒,将时间 h2:m2:s2 化作这一天过去了 $t2$ 秒。例如说,如果现在是 01:00:00,那么相当于这一天过去了 $3600$ 秒。
因为 $1$ 小时等于 $60$ 分钟等于 $3600$ 秒,因此我们可以编写这一段代码:
int t1 = h1 * 3600 + m1 * 60 + s1;
int t2 = h2 * 3600 + m2 * 60 + s2;
接着,时间有两种情况:一种情况是小 X 睡觉和闹钟响了是同一天;另外一种情况是闹钟响了是小 X 睡觉次日发生的事情。在本题中,如果 $t1>t2$,那么是第一种情况;如果 $t108:30:00,此时 $t2=30600$,满足 $t1>t2$,即小 X 睡觉和闹钟响了是同一天。
对于同一天的情况是好处理的,只需计算两个时间 $t1,t2$ 的差。如果是次日,那么需要用 $t1$ 和 $t2$ 的差,加上一天的时间,才能得到正确的结果。
if (t1 > t2)
ans = t1 - t2;
else
ans = t1 + 86400 - t2;
最后,将这个差值(单位:秒)转换为时分秒的格式。参考代码:
cout << ans / 3600 << " " // 时
<< ans / 60 % 60 << " " // 分
<< ans % 60; // 秒
T3¶
本题考察分支结构。
矩形的面积可以根据矩形左上角和右下角的坐标得知。假设矩形左上角的坐标是 $(x_a,y_a)$,右下角的坐标是 $(x_b,y_b)$,那么矩形的面积就是长 $\times$ 宽,也就是 $(x_b−x_a)\times (y_b−y_a)$。
因此,只需要记录下 $x_1,x_2,x_3,x_4$ 和 $y_1,y_2,y_3,y_4$ 的最小值、最大值,然后计算两个差值的乘积。
参考代码(部分):
// 找出 x 的最小值和最大值
int min_x = x1;
if (x2 < min_x) min_x = x2;
if (x3 < min_x) min_x = x3;
if (x4 < min_x) min_x = x4;
int max_x = x1;
if (x2 > max_x) max_x = x2;
if (x3 > max_x) max_x = x3;
if (x4 > max_x) max_x = x4;
(中间省略)
cout << (max_x - min_x) * (max_y - min_y) << endl;
T4¶
本题考察分支结构。
我们需要计算出每种方案小 X 需要花费多少时间,再从中选择最小值。根据题意:
- 步行。所需时间是:
n / a - 坐公交车。所需时间是
t + n / b - 骑单车,时间是
m / a + (m + n) / c
在编写代码的时候,由于时间都有可能是小数,因此需要使用 double 类型变量存储这些数值。但是由于 $a$,$b$,$c$ 是整数,整数除以整数的结果是整数,因此需要将其强制转换为浮点数。参考代码:
double walk_time = 1.0 * n / a;
double bus_time = t + 1.0 * n / b;
double bike_time = (1.0 * m / a) + 1.0 * (n + m) / c;
接着从中选择最小值输出即可。注意需要输出的是保留到小数点后两位的浮点数,需要使用 printf("%.2lf", ans) 这样的形式输出。
例如步行时间如果最短可以采取如下方式
if (walk_time <= bus_time && walk_time <= bike_time)
{
cout << "MODE I" << endl;
printf("%.2lf", walk_time);
}
T5¶
本题考察循环结构。
由于这是一个拥有 $n$ 天的训练计划,因此可以使用循环读入每天的学习值 $a_i$,在循环内套上一个分支语句,计算专注度以及对应的学习值即可。
参考代码:
for (int i = 0; i < n; ++i)
{
cin >> ai;
if (S >= m)
{ // S 的值大于等于认真阈值 m
sum += ai * 2; // 获得双倍学习值
S /= 2; // 专注度减半
}
else
{ // S 的值小于认真阈值 m
sum += ai / 2; // 获得一半学习值
S += ai; // 专注度增加 ai
}
}
T6¶
本题考察循环嵌套。
外面大矩形的边长为 $a$,而中间挖掉的正方形的边长为 $b$,可以得知:在第 $\dfrac{a-b}{2}+1$ 行列到第 $\dfrac{a+b}{2}$ 行列是需要被挖空的。
以样例的 $a=6,b=2$ 为例,第 $\dfrac{6-2}{2}+1=3$ 行列到第 $\dfrac{6+2}{2}=5$ 行列需要被挖空。
因此我们可以计算得到挖空区域的起始和终止位置。
int st = (a - b) / 2 + 1; int ed = (a + b) / 2;
接着设计一个二重循环,外层 $i$ 循环行数,内层 $j$ 循环列数,判断当前位置是否是需要被挖空的即可完成本题。
参考代码(部分):
for (int i = 1; i <= a; i++)
{
for (int j = 1; j <= a; j++)
{
if (i >= st && i <= ed && j >= st && j <= ed)
cout << ' ';
else
cout << '*';
}
cout << endl; // 每行结束后换行
}
T7¶
本题考察数论。
$n!$ 的末尾有多少个 $0$,相当于乘上了多少个 $2\times 5$(也就是 $10$),这里需要注意,对于每个乘数都需要质因数分解,例如 $8=2\times 2\times 2$,$10=2\times 5$。
由于乘上的 $2$ 肯定比乘上的 $5$ 多,因此只需考察一共乘上了多少个 $5$。在 $n$ 以内,一共有 $n\div 5$ 个 $5$ 的倍数。然而,$25=5\times 5$,应该还需对答案有一次贡献;$125=5\times 5\times 5$,还需要对答案有一次贡献 $\ldots$。
因此答案就是:$n$ 以内有多少个 $5,25,125,625,\ldots$ 的倍数。可以使用循环语句完成这一题。
参考代码:
while (n > 0)
{
ans += n / 5;
n /= 5;
}