Как стать автором
Обновить

Разбор теста от MixBytes

Время на прочтение4 мин
Количество просмотров2.3K

Не так давно компания MixBytes проводила конкурс, пройдя который можно было попасть на их курс аудитора смарт-контрактов
Здесь публикую свой разбор этого теста

1-е задание
Ответ

Я не профи в питоне. Поэтому изначально полез гуглить что вообще тут за функции. Первое, что бросается в глаза: random.seed() при одинаковом параметре будет возвращать одинаковый результат.

Тут есть 2 подхода как найти решение: понять код самостоятельно или прогнать в компиляторе\интерпретаторе.

Начну с самостоятельного понимания.
Почитав про range и random в питоне, становится ясно: последняя строчка генерирует результат в диапазоне от 0 до (1e12)-1. Т.е всего 1e12 вариантов

Кто не понял что такое 1e12 - это тоже вполне гуглится

Честно говоря, давно с формулами теории вероятности дело не имел. Могу предположить, что дальнейшее повествование приведёт к правильному ответу основываясь на неверных вычислениях: как в примере со сломанными часами, которые 2-жды в сутки показывают правильное время. Если где-то ошибся - надеюсь, читатели поправят.
Для полноты картины полезно было бы почитать про расчёт вероятности зависимых и независимых событий... Но, можно рассуждать по-другому.
Вероятность p выпадения любого числа в выше названном промежутке = 1/1e12
С учётом фиксированного random.seed(), вероятность 10 раз получить одинаковое число (не важно какое именно) = 100% (т.е. 1)

Итого: p = 1/1e12 * 1 = 1/1e12

Если хочется считать через зависимые\независимые события, то можно понять, что с зафиксированным random.seed() события нельзя считать зависимыми: на любом шаге будет выпадать то же число (с вероятностью 1/1e12), что и на любом другом шаге. Т.е. одна и та же вероятность на каждом шаге 1/1e12 складывается 10 раз и делится на количество вызовов (10)

Т.е. формула: p = ((1/1e12) * 10)/10
Т.е. итог: 1/1e12

С использованием онлайн интерпретатора (гуглятся и находятся несколько разных без проблем) ещё интересней.
Чтоб поиграться с кодом, чутка переделаем его в:

import random

def generate():
    random.seed(12345)
    print("res: ", random.choice(list(range(int(1e12)))))
    
generate()

При попытке его запуска получим ошибку:
** Process exited due to resource limitations **

Но, играя со степенями 1e можно заметить закономерность:

1e1 = 6
1e2 = 53
1e3 = 426
1e4 = 6825

И т.д. Значения всегда только увеличиваются. Из этого вывод: если бы код работал при 1e12 вероятность была бы = 0.

Итого: у задачи фактически 2 ответа, смотря с какой стороны подходить к решению: 1/1e12 и 0

Как выяснилось, любой из этих 2-х ответов засчитывался.

2-е задание
Ответ

На мой взгляд, самое простое задание. Настолько простое, что даже не знаю: что тут объяснять... sqrt() - функция квадратного корня. ^ - возведение в степень.
Самостоятельно написав код по формуле я увидел, что ответ будет - первый вариант. Строго соблюдая ту же последовательность вычислений, что в формуле.

3-е задание
Ответ

unsigned - без знаковое. Значит, при вычислениях отбрасываем значения после запятой.

a1 = 1234 / 123 = 10a2 = 1234 / 12 = 102a1 = 10 *  123 = 1230a2 = 102 * 12 = 1224

Итого: 4 вариант

4-е задание
Ответ

На эту задачу я изначально неверно ответил. Но, ход мыслей был верный.

26 букв одного регистра. Значит, верхнего и нижнего регистра 26 *2 = 52. Добавим цифры (0...9). Всего 62
Теперь посмотрим на эти 2 строчки:

12345678
yo

Сколько различных комбинаций, где yo будет на разных местах? Двигая yo можно увидеть, что их 7.

Если из 8 символов нужно перебрать оставшиеся 6 (т.к. yo - это 2 символа) - получим:

62^6

Учитывая, вышесказанное про 7 различных позиций yo в строке из 8 символов получим:

62^6*7

Т.е. это 5 вариант - как раз мной выбранный. Но, тут ошибка. Верным считался ответ - 6 вариант:

62^6*7-1

Дело в том, что если перебрали 62^6*7-1 и хеш не совпал, то последний должен совпасть автоматически и его не нужно для этого считать.

Были ещё высказаны верные замечания различными участниками, что задачка всё равно не однозначная. Допустим, если на 1-м шаге перебраны все значения yo******, то на 3-м (**yo****) не нужно считать вариант yoyo****, т.к. он уже был на 1-м шаге. Авторы теста согласились, что это в логике задачи не учитывалось.

5-е задание
Ответ

Начнём считать все варианты функции начиная с 0

x(0) = 0x(1) = 1x(2) = x(1) + x(0) + 3 = 4x(3) = x(2) + x(1) + 3 = 8x(4) = x(3) + x(2) + 3 = 8 + 4 + 3 = 15x(5) = x(4) + x(3) + 3 = 15 + 8 + 3 = 26x(6) = x(5) + x(4) + 3 = 26 + 15 + 3 = 44x(7) = x(6) + x(5) + 3 = 44 + 26 + 3 = 73x(8) = x(7) + x(6) + 3 = 73 + 44 + 3 = 120x(9) = x(8) + x(7) + 3 = 120 + 73 + 3 = 196

Итого: ответ - 2 вариант

6-е задание
Ответ

Сама задача не вызвала вопросов. А вот понять ответы сходу было проблемно. Ясно было одно: ответы смотреть нужно из вариантов: 5-7. Т.к. по условиям даже одна строка не факт, что поместится в память. Значит, в память загружать блоками, которые точно влезут в память. И важно прочесть условие задачи: найти наибольшее число строк, идущих подряд. А не все одинаковые строки без разбора на какой позиции

Итеративный хеш на примере простой строки: 12345\n
Пусть блок N = 1
Считаем хеш от 1: h1 = h(1)
Следующий хеш: h2 = (h(1)+'2')
Последний хеш: h6 = (h(5)+'\n')
h6 будет уникальным хешем для строки, который получили итеративно. Если строка повторилась Х раз - значит, Х раз будет повторяться хеш h6. Считаем Х - максимальным числом (т.е. счётчиком повторений), пока не найдётся ситуация, где итеративный хеш для строки повторится Y раз, где Y > Х . В этом случае запишем Y. И т.д. По этому описанию подходит 7 вариант


8-е задание
Ответ

Сначала стоит разобраться с APR и APY. Сейчас я не могу найти хорошей статьи, которую нашёл в процессе решения задачи. Но, помню, что APY - это сложные проценты. Т.е. как раз тот случай, когда можно накопленное за период (период для Коли - месяц, для Пети - день), перезакладывать на следующий период

С калькулятором считать замучаешься. Набросав код на Solidity и проверив его в Remix для относительно больших чисел (например, 10000000000). Получим 4-й вариант.

contract dop {

    function monthly(uint256 num) public pure returns (uint256) {
        for (uint i = 0; i < 12; i++)
        {
            num = num + (num*2)/120; // 2/120 это 20% и 12 месяцев
        }
        return num;
    }

    function daily(uint256 num) public pure returns (uint256) {
        for (uint i = 0; i < 360; i++)
        {
            num = num + (num*20)/36000; // 20% и 360 дней
        }
        return num;
    }
}

9-е задание
Ответ

С этим я провозился больше всего. Пришёл 1 нормальный вариант: в стартовом вагоне включить свет, в любую сторону идти до вагона, где свет включен, выключить его и проверить выключился ли в стартовом (т.е. возвращаться, запоминая сколько вагонов прошёл). Повторять процедуру пока в стартовом свет не погаснет.

А где же 7-е задание?

Авторы задания признали его неверным

Теги:
Хабы:
Всего голосов 6: ↑4 и ↓2+6
Комментарии1

Публикации

Истории

Работа

Ближайшие события

19 августа – 20 октября
RuCode.Финал. Чемпионат по алгоритмическому программированию и ИИ
МоскваНижний НовгородЕкатеринбургСтавропольНовосибрискКалининградПермьВладивостокЧитаКраснорскТомскИжевскПетрозаводскКазаньКурскТюменьВолгоградУфаМурманскБишкекСочиУльяновскСаратовИркутскДолгопрудныйОнлайн
24 – 25 октября
One Day Offer для AQA Engineer и Developers
Онлайн
25 октября
Конференция по росту продуктов EGC’24
МоскваОнлайн
26 октября
ProIT Network Fest
Санкт-Петербург
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань