Revision ru23, by nikich340, 2017-08-15 02:06:12

А. Ярмарка оружия [реализация, математика]

Необходимо последовательно сравнить силы наборов, если текущая сила строго больше максимальной предыдущей, то обновляем максимальную и индекс лучшего набора. Вычислить силу набора можно было в нецелых числах как (сумма si, j / wi), или сохранить числитель и знаменатель дроби (sumsmax и wmax) и сравнивая с текущим набором домножить обе части на (wmax·wi). Не стоит забывать, что суммирование 105 чисел до 109 приведёт к переполнению типа integer.

Асимптотика: O(n·max(wi))

Код в нецелых числах

Код в целых числах

B. Имённо-фамильный никнейм [перебор, строки]

Любое решение сводится к тому, чтобы максимизировать подстроку в n (ведь чем больше символов мы возьмём из n, тем меньше потребуется из f).

Обозначим длину такой подстроки за k.

1) Наивное решение может проверять все подстроки строки n для поиска максимального k, после чего искать недостающий конец строки в f. Это будет работать за O(q·|n|2 + q·|f|) в теории, однако лишь в худшем частном случае, когда множество раз наблюдается значительное совпадение подстроки с первой часть строки si (пример: n = " ", f = " ", и все si = " ").

Код

2) Подсчитать все возможные подстроки для n за |n|2, сложить в set[string] или бор, или подсчитать хеши (это будет работать аналогично set[string]). Теперь для каждого si можно последовательно искать k, после чего можно пройтись последовательно по f, узнав, есть ли там оставшиеся |si| - k символов. При использовании set[string] или хешей можно также искать k бинарным поиском, укорачивая или удлиняя текущую строку до длины M на каждой итерации и ища ей соответствие в подстроках n.

Асимптотики такого решения:

  • Для хешей или set:
    • если искать k последовательно: O(q·k·log2(|n|2) + q·|f|)
    • бинарным поиском: O(q·log2(klog2(|n|2) + q·|f|)
  • Для бора: O(q·k + q·|f|)

Код с set[string], последовательная проверка k

Код с set[string], бинарный поиск по k

Код с бором

3) Развернём n, f, и si задом наперёд. Тогда нам нужно максимизировать не подстроку, а подпоследовательность в f, в этом единственное отличие от предыдущего варианта. Искать k для подпоследовательности можно только последовательно, после чего нам нужно найти в n подстроку длины |n| - k, для чего опять же следует предподсчитать все возможные подстроки для n за |n|2 и сложить их в какую-нибудь структуру.

Асимптотика решения:

  • Для хешей или set[string]: O(q·k + q·log2(|n|2))
  • Для бора: O(q·k + q·|n|)

C. Два великана [игры, математика]

Очевидно, что размер кучи от 1 до x является выигрышным для Тора, т.к. он может сломать её одним ударом.

А теперь давайте подумаем насчет n = x + 1. Если Тор сломает 1 кирпич, останется x кирпичей, и Арен победит, если Тор сломает x кирпичей, Арену останется 1 кирпич и он тоже выиграет.

Значит, куча размера x + 1 всегда является проигрышной для Тора. А это в свою очередь значит, что все кучи от x + 2 до 2x + 1 являются выигрышными — Тор может всегда сломать столько кирпичей, что Арену достанется куча размера x + 1 и тот проиграет.

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

И получаем, что проигрышными для Тора являются только кучи кратные x + 1 (x + 1, 2x + 2, 3x + 3, ..). Тогда ответ на отрезке [1;n] можно найти как , обозначим это функцией f(n), тогда ответ на отрезке [L;R] равняется f(R) - f(L - 1).

Асимптотика: O(q)

Код

D. Кровожадная функция [математика]

Итак, f(x) = ax·(b + x)x·c. Нам даны три значения этой функции, давайте распишем их в полном виде:

f(0) = a0·(b + 0)0·c = 1·1·c = c

f(1) = a1·(b + 1)1·c = a·(b + 1)·c

f(2) = a2·(b + 2)2·c

Как видим, c = f(0). Значит можно упростить два других выражения:

Что мешает избавиться от квадрата во втором выражении?

Теперь можно найти a:

И b:

Асимптотика: O(1)

Код

E. Интересная структура [математика, реализация]

Так как x не превосходит 100, можно было хранить массив cnt[100] и прибавлять или отнимать количество чисел в явном виде. При запросе третьего типа необходимо пройтись по всем числам от 1 до 100 и умножить текущий остаток на xcnt[x] по модулю m.

Однако cnt[x] может быть весьма большим, и каждый раз умножать в явном виде слишком долго. Здесь есть два пути оптимизации:

1) будем хранить стек значений val[x], где val[x][cnt[x]] равняется xcnt[x] % m. Сделаем val[x][0] = 1 изначально для всех x от 1 о 100, тогда при добавлении нового числа x в структуру будем помешать в конец стека новое значение на основе предыдущего: val[x].push_back( (val[x][ cnt[x] ] * x) % m ); А при запросе второго типа нам просто нужно убрать последнее значение из стека: val[x].pop_back().

Также вместо стека можно было использовать массив val[100][100000] (т.к. очевидно что любое число будет повторяться не более q раз, т.е. не более 105 раз), но это более затратно по памяти.

Асимптотика: O(q + 100·cntt3)

Код со стеком

Код с массивом

2) воспользуемся быстрым возведением в степень (более подробно здесь, основная идея в том, что xn = xn / 2·xn / 2)

Асимптотика: O(q + 100·cntt3·log2(cnt[x]).

Код

+) можно не пересчитывать ответ каждый раз на запрос третьего типа, а лишь в тех случаях когда мы вносили изменение (т.е. это оптимизация на случай множественный запросов третьего типа).

+) можно хранить числа не в явном виде, а факторизовать их (раскладывать на простые) и считать ответ по степеням простых чисел от 1 до 100 (их 25 штук). Авторское решение использовало именно факторизацию + быстрое возведение в степень: O(q·log2(x) + 25·cntt3·log2(cnt[x])).

Код авторского решения

F. Статически полный граф [тролль]

Если Вы хоть немного знаете о том, что такое графы, Вы сможете решить эту задачу.

Главное — внимательно прочитать все условия и подумать что они означают.

Tags разбор, двгупс, тренировка

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
ru23 Russian nikich340 2017-08-15 02:06:12 57
ru22 Russian nikich340 2017-08-14 03:38:53 0 (опубликовано)
ru21 Russian nikich340 2017-08-14 03:37:24 0
ru20 Russian nikich340 2017-08-14 03:37:24 6
ru19 Russian nikich340 2017-08-14 03:35:31 879 Мелкая правка: 'няется $x^cnt[x] % m$. Сде' -> 'няется $x^{cnt[x]} % m$. Сде'
ru18 Russian nikich340 2017-08-14 03:21:52 1685
ru17 Russian nikich340 2017-08-14 02:55:25 337 Мелкая правка: '(b + 1)$\n$\frac{f' -> '(b + 1)$\n\n$\frac{f'
ru16 Russian nikich340 2017-08-14 02:47:51 294
ru15 Russian nikich340 2017-08-14 02:43:54 387
ru14 Russian nikich340 2017-08-14 02:38:00 2110
ru13 Russian nikich340 2017-08-14 02:19:17 112
ru12 Russian nikich340 2017-08-14 02:17:37 2 Мелкая правка: 'руктуру.\nАсимптот' -> 'руктуру.\n\nАсимптот'
ru11 Russian nikich340 2017-08-14 02:16:48 72 Мелкая правка: 'решения:\n- Для хе' -> 'решения:\n\n- Для хе'
ru10 Russian nikich340 2017-08-14 02:14:24 189
ru9 Russian nikich340 2017-08-13 15:40:50 4
ru8 Russian nikich340 2017-08-13 15:39:04 139
ru7 Russian nikich340 2017-08-13 15:35:40 15
ru6 Russian nikich340 2017-08-13 15:34:54 10
ru5 Russian nikich340 2017-08-13 15:33:54 427
ru4 Russian nikich340 2017-08-13 15:20:03 2245 Мелкая правка: 'ематика]\nСледовал' -> 'ематика]\n\nСледовал'
ru3 Russian nikich340 2017-08-13 15:15:48 16
ru2 Russian nikich340 2017-08-13 15:15:20 616
ru1 Russian nikich340 2017-08-13 14:57:12 113 Первая редакция (сохранено в черновиках)