引言
早在2018年10月,我们就很高兴地记得2017年任务的出现日历(条件在
此处 ),并开始考虑今年可以做什么。 在几个有价值的想法中,我们选择了一个选项,在其中选择各种“醒目的”任务,并结合一个美好的新年故事。
什么都没剩下:实际上,接任务,撰写故事,建立一个带有排行榜的网站,与Yandex紧密联系的漂亮比赛。然后在12月初开始:-)
结果
如您所知,食欲伴随着进食,我们全力投入到制定任务内容及其技术实施的过程中。 每个成功的发现都激发了进一步的改进。 结果,我们为其中一项任务举起了单独的服务器,为另一项任务做了优化(我们自己没有确切的答案),自己录制了音乐,恢复了发行状态—我们一点也不觉得无聊!
结果是:
有趣的事实和故事
注册了780位参与者,开始解决333人,成功完成至少两项任务的203人。
最初,我们估计无准备的参与者解决所有问题的净时间为7天,而经验丰富的参与者(又称CS中心应届毕业生)则为2天。 圣诞老人的第一位助手正确地解决了所有十一项任务,大约一天的时间就完成了,第二名又完成了第二位!
一位与会者的来信:“下午好! 由于您的竞赛,我专门停了办公室(40人),这是关于圣诞老人咖啡的第二项任务,请给我一个提示。 我们都很受折磨。”
解析任务
条款
在这里 。
任务D“音乐讯息”(米哈伊尔·普洛特金)解决这个问题非常简单,只需很少的音乐教育。
尝试以有节奏的方式寻找线索并没有成功。 下一个想法是坐在钢琴旁拾起您所听到的音乐。 原来,la,do,mi,si,la,re,salt,mi。 在这样的高音谱号中:

在前三个音符之后,稍作停顿,好像将音乐短语分为两个单词一样。 只剩下用传统字母符号写笔记(A = la,B = si,C = do,D = pe,E = mi,F = fa,G =盐),并且打开了两个单词:ACE BADGE。
没有任何音乐素养知识,解决问题就更加困难。 例如,可以使用某种程序来处理声音,并找出音符本身或以赫兹为单位的声音频率,然后找出哪些频率对应于哪些音符。
该任务要求不使用分隔符一起写字母,因此答案是ACEBADGE。
任务F“雪花袋”(米哈伊尔·普洛特金)初始三角形的面积为1。接下来,在第n步,添加t_n个三角形,每个三角形的面积为s_n。 结果图形的总面积表示为无穷级数的总和:
S = 1 +Σ(t_n * s_n), n上的和为 0到∞(1)
在零步处,t_0 = 3,s_0 = 1/9,因为该三角形有3个边,因此在每个三角形上都建有一个边,该边的边比原始边小3倍,因此面积比原始边的面积小9倍。
在接下来的每一步中,每一边变成4边,小三倍,即
t_n = t_ {n-1} * 4 = t_0 * 4n = 3 * 4n,
s_n = s_ {n-1} *(1/9)= s_0 *(1/9)^ n = 1/9 *(1/9)^ n。
因此,所需区域:
S = 1 +Σ(t_n * s_n)= 1 + 1/3 *Σ((4/9)^ n),n的总和是从0到∞(2)
第二项是无限递减的几何级数之和。 要计算,请使用学校公式
Σ((4/9)^ n)= 1 /(1-4/9)= 9/5。
代入公式(2),我们得到答案:
S = 1 + 1/3 * 9/5 = 8/5 = 1.6
任务G和L“路线已建立”(Artyom Romanov)感谢Artyom
mehrunesartem提供的解决方案! 顺便说一句,问题G中使用的图形基于伦敦地铁(London Underground):)
为了解决这个问题,我们将使用广度优先搜索的修改版本。 我们得到一个虚构的顶点(源),从中我们在图形的每个顶点处绘制权重为零的边。 每个状态由从源传递的路径唯一确定。 此外,我们将存储花费的时间和所获得的喜悦。
我们以固定大小启动优先级队列,并在其中放入状态。 为了评估队列中的条件,我们将使用收到的幸福感与花费的时间之比。 此评估是不正确的,但在此任务中显示出良好的结果。
在每个步骤中,我们将从队列中获得具有最佳估计值的状态,并将由此形成的状态放入队列中。 使用这种方法,将需要很长时间才能获得最终结果。
为了加快解决方案的速度,我们将逐步寻找答案。 在每个步骤中,要搜索路径中的下一个顶点,我们将清除队列并将当前状态放入其中。 然后,我们将执行固定数量的步骤,同时更新提供最大欢乐的状态。 作为路径的下一个顶点,在产生最大欢乐程度的结果状态的路径中,采用当前状态的最后一个顶点之后的顶点。 我们重复完成的动作,直到可以改善当前状态为止。
可能的改进
- 使用最佳启发式方法。
- 通过该算法的实现,将会出现额外的状态,因为在每一步中,我们都将添加可能来自当前状态的所有状态。 为了避免这种情况,请使用Dijkstra算法,对于图的每个顶点,您可以首先构建到所有其他顶点的最短路径的树,然后不一步一步地进行过渡,而是沿着构建的树进行过渡,直到我们到达从未去过的顶点为止。
这些更改没有带来明显的改善,这很可能是由于只有一个封闭测试,而不是一组不同的生成测试。
任务一“熊数字化仪”(亚历山大·萨莫法洛夫)让我们看一下服务的
源代码 。
可以从
/data
获取用户可用的所有ID的列表。
如果存在id,则可以使用对address
/data/id
的请求来获取
/data/id
。
要访问数据,该服务需要令牌进行身份验证。 我们有一个可用的
令牌 ,但它已过期,服务不再接受它。
让我们在代码中查看
如何生成这些令牌 。 通过加密格式为
{ “userId” : “id”, expireDate: “date”}
JSON,然后在base64中对其进行编码,可以获取令牌。 该服务使用RSA进行加密,可以通过
/key
的请求获得
/key
。
让我们提出一个请求:e = 30593,n = 66043。 n足够小,那么我们可以轻松计算出私钥。
为此,我们将n分解为主要因子:211 * 313。
我们计算n
的Euler函数 :φ(n)=(211-1)(313-1)= 65520。
我们得到d = e-1(modφ(n))= 257。
可以使用
高级欧几里得算法来计算逆元模。
计算私钥后,我们解密可用的令牌。
我们得到以下JSON:
{"userId":"448f0a79-e2d8-4ccd-9009-53858914dcaa","expireDate":"2018-12-06T14:38:00.898026+00:00"}
请注意,具有给定userId的用户
的服务足以存在,且expireDate小于服务器上的当前时间。
也就是说,知道userId后,我们可以生成一个新的有效令牌。
为此,请将expireDate设置得足够大以通过测试-例如
{"userId":"448f0a79-e2d8-4ccd-9009-53858914dcaa","expireDate":"2100-01-01T12:00:00.000000+00:00"}
。
我们使用公钥加密新令牌。
向
/data
请求后,我们发现用户创建的消息的标识符为1到4。
我们将全力以赴。
其中有一个奇妙的短语:
新年快要敲门了,快打开吧! 。
解决其他一些问题的技巧(来自Artyom Romanov)任务A“带字母的保险箱”您可能会注意到,每二十步您将获得相同的数字。
任务B“教授的秘密”按受欢迎程度降序对单词进行排序。 您可能会注意到每个后续单词出现在大约2、3、4等中。 比最流行的单词少一倍。 现在您可以恢复答案了。
任务J“孟加拉语”可能的位置:

问题K“冷淡花纹”要解决此问题,您可以选择任何方便的三角形,例如右三角形,并为其计算答案。
致谢
从构思到实施的整个过程都是由Katya Lebedeva驱动和协调的。 Katya Artamonova,Alina Mozhina,Sasha Komissarov和我帮助她完成了任务。 Lyosha Tolstikov编写了三个复杂的检查器,Sasha Komissarov和Seryozha Zherevchuk制作了服务器,Svyato和Seryozha无私地制作了一个与任务紧密集成的漂亮网站:每个参与者都可以看到他的进度和排行榜。