跳转至

语法周赛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$,那么是第一种情况;如果 $t119:00:00,此时 $t1=68400$,而小 X 的睡觉时间是 08: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;
}