语法周赛 Round 6 题解
2024年12月25日大约 4 分钟
A.桃园南路上的红绿灯
分析
- 难度:知道数学中周期的概念,然后简单条件判断即可。如果实在搞不清楚的,也可以直接用循环模拟处理。
- 子任务 1(30 分):只有红灯,输出
red
就好。 - 子任务 2(30 分):没有黄灯,只有红灯和绿灯,每个周期只有两种颜色了,处理起来会方便一点(其实也差不多)。
- 子任务 3(40 分):循环模拟的做法略,第一题咱不考虑高阶语法的做法。首先可以算出每个周期的长度
。这题主要目的就是给大家强化从 开始和从 开始的区别。可以先把 分钟通过减 转换到 ,然后通过 就可以得到第一个周期的结果,然后再加 就可以从 转换回 了。当然也可以一开始就给 减少 ,然后每个灯的时间看成 是红灯、 是黄灯,以此类推。
满分参考代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x, y, z, q;
cin >> x >> y >> z >> q;
int t = x + y + z + y;
q = (q - 1) % t + 1;
if (q <= x)
cout << "red";
else if (q <= x + y)
cout << "yellow";
else if (q <= x + y + z)
cout << "green";
else
cout << "yellow";
return 0;
}
B.不太随机的随机数列
分析
- 难度:打表找规律!
- 子任务 1(30 分):
非常小,把死循环改成循环执行 次,然后只在第 次输出即可。 - 子任务 2(30 分):虽然
很大,但是这里是等于号,也就是告诉了大家测试点的输入,所以不需要实时算出这一项,自己在本地跑出来结果后,当 时直接输出答案就好。 - 子任务 3(40 分):子任务 2 主要就是提醒大家可以本地打表,如果你执行上面的代码输出前
项,很容易发现中间会出现循环的结果。前两项分别是 和 ,第 项是 而第 项也是 ,所以 是一个周期,周期长度为 。去掉前两项之后的 项就是每 个数是一样的,直接按照类似于第一题的方式处理即可。这样能把数据缩小到 以内,直接用子任务 1 的方式处理即可。
满分参考代码
#include <bits/stdc++.h>
using namespace std;
// 1:33 2:157 3:184 ... 30:76 31:184
const int t = 30 - 3 + 1;
int main()
{
long long x;
cin >> x;
assert(1LL <= x && x <= 1'000'000'000'000LL);
if (x > 2)
{
long long partA = 2;
long long partB = x - 2;
partB = (partB - 1) % t + 1;
x = partA + partB;
}
int seed = 33;
for (int i = 1; i <= x; i++)
{
if (i == x)
cout << seed << '\n';
seed = seed * seed % 233;
}
return 0;
}
C.假装在洗一副扑克牌
分析
- 难度:简单的字符串处理
- 子任务 1(30 分):只有一张牌,原样输出即可。
- 子任务 2(30 分):没有
10
,那就是逆序输出字符串。 - 子任务 3(40 分):逆序输出时遇到
01
就输出10
即可。下面给出常规做法之外,另外再给出一个有趣的递归形式。
满分参考代码
在遇到 s.size()-1
的形式时大家需要注意,s.size()
的返回值是无符号整型,所以当字符串为空、s.size()
为 0
时,减一就会变成无符号整型的最大值。所以建议如果要减 int
后再处理。(当然这题的字符串长度保证大于等于
李知颖的满分代码
#include<iostream>
using namespace std;
string a;
int n;
int main()
{
cin>>a;
n=a.size();
for(int i=n-1;i>=0;i--)
{
if(a[i]=='0'&&a[i-1]=='1')
{
cout<<10;
i--;
}
else
cout<<a[i];
}
return 0;
}
有趣的递归形式实现逆序输出
#include <bits/stdc++.h>
using namespace std;
string s;
void f(int l, int r)
{
if (l > r)
return;
if (s[l] == '1')
{
f(l + 2, r);
cout << "10";
}
else
{
f(l + 1, r);
cout << s[l];
}
}
int main()
{
cin >> s;
f(0, (int)s.size() - 1);
return 0;
}
D.可持久化入门之数对
分析
- 难度:主要难度在于读题,读题搞定后,就是一个简单的模拟题了。
- 子任务 1(30 分):因为只有操作 2,没有修改,所以每个版本的两个数都一样。每次询问时根据
来决定输出 还是 即可。 - 子任务 2(30 分):因为操作的数只有第一个数,所以就是个一维数组的模拟了。每次先
a[i] = a[vi];
复制一份,然后看看是改还是输出就好。 - 子任务 3(40 分):在子任务 2 的基础上,从维护一个数改成维护两个数就好。每次操作前先复制一份,然后处理当前数对即可。
满分参考代码
#include <bits/stdc++.h>
using namespace std;
int M;
int a[105][3];
int main()
{
cin >> M;
cin >> a[0][1] >> a[0][2];
for (int i = 1; i <= M; i++)
{
int v, op, loc, val;
cin >> v >> op;
a[i][1] = a[v][1];
a[i][2] = a[v][2];
if (op == 1)
{
cin >> loc >> val;
a[i][loc] = val;
}
if (op == 2)
{
cin >> loc;
cout << a[i][loc] << "\n";
}
}
return 0;
}