CS Center 2018除夕比赛

引言


早在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):)

为了解决这个问题,我们将使用广度优先搜索的修改版本。 我们得到一个虚构的顶点(源),从中我们在图形的每个顶点处绘制权重为零的边。 每个状态由从源传递的路径唯一确定。 此外,我们将存储花费的时间和所获得的喜悦。

我们以固定大小启动优先级队列,并在其中放入状态。 为了评估队列中的条件,我们将使用收到的幸福感与花费的时间之比。 此评估是不正确的,但在此任务中显示出良好的结果。
在每个步骤中,我们将从队列中获得具有最佳估计值的状态,并将由此形成的状态放入队列中。 使用这种方法,将需要很长时间才能获得最终结果。

为了加快解决方案的速度,我们将逐步寻找答案。 在每个步骤中,要搜索路径中的下一个顶点,我们将清除队列并将当前状态放入其中。 然后,我们将执行固定数量的步骤,同时更新提供最大欢乐的状态。 作为路径的下一个顶点,在产生最大欢乐程度的结果状态的路径中,采用当前状态的最后一个顶点之后的顶点。 我们重复完成的动作,直到可以改善当前状态为止。

可能的改进

  1. 使用最佳启发式方法。
  2. 通过该算法的实现,将会出现额外的状态,因为在每一步中,我们都将添加可能来自当前状态的所有状态。 为了避免这种情况,请使用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等中。 比最流行的单词少一倍。 现在您可以恢复答案了。

任务C“计算机灾难”
想想空白编程语言。

任务J“孟加拉语”
可能的位置:


问题K“冷淡花纹”
要解决此问题,您可以选择任何方便的三角形,例如右三角形,并为其计算答案。

致谢


从构思到实施的整个过程都是由Katya Lebedeva驱动和协调的。 Katya Artamonova,Alina Mozhina,Sasha Komissarov和我帮助她完成了任务。 Lyosha Tolstikov编写了三个复杂的检查器,Sasha Komissarov和Seryozha Zherevchuk制作了服务器,Svyato和Seryozha无私地制作了一个与任务紧密集成的漂亮网站:每个参与者都可以看到他的进度和排行榜。

Source: https://habr.com/ru/post/zh-CN438570/


All Articles