Теорема об остатках в Китае говорит нам, что мы всегда можем найти число, которое дает любые необходимые остатки при различных простых модулях. Ваша цель - написать код для вывода такого числа за полиномиальное время. Самый короткий код выигрывает.
Например, скажем, мы получили эти ограничения ( %
представляет мод):
n % 7 == 2
n % 5 == 4
n % 11 == 0
Одним из решений является n=44
. Первое ограничение выполняется потому 44 = 6*7 + 2
, что и так 44
имеет остаток 2
при делении на 7
, и, таким образом 44 % 7 == 2
. Два других ограничения также выполнены. Существуют и другие решения, такие как n=814
и n=-341
.
вход
Непустой список пар (p_i,a_i)
, где каждый модуль p_i
представляет собой отдельное простое число, а каждая цель a_i
- натуральное число в диапазоне 0 <= a_i < p_i
. Вы можете принять участие в любой удобной форме; это не обязательно должен быть список пар. Вы не можете предполагать, что вход отсортирован.
Выход
Целое число n
такое, что n % p_i == a_i
для каждого индекса i
. Это не должно быть наименьшее такое значение, и может быть отрицательным.
Полиномиальное ограничение по времени
Чтобы предотвратить дешевые решения , которые просто пытаются n=0
, n=1
, n=2
и так далее, ваш код должен работать в полиномиальное время в длине ввода . Обратите внимание, что число m
во входных данных имеет длину Θ(log m)
, поэтому m
само по себе оно не является полиномиальным по своей длине. Это означает, что вы не можете рассчитывать m
или выполнять время операции m
, но вы можете вычислять арифметические операции над значениями.
Вы не можете использовать неэффективный формат ввода, такой как унарный, чтобы обойти это.
Другие запреты
Не допускаются встроенные функции для выполнения следующих действий: Реализация теоремы китайского остатка, решение уравнений или факторных чисел.
Вы можете использовать встроенные модули для поиска модов и выполнения модульного сложения, вычитания, умножения и возведения в степень (с показателем натурального числа). Вы не можете использовать другие встроенные модульные операции, включая модульное обратное, деление и поиск заказа.
Контрольные примеры
Они дают наименьшее неотрицательное решение. Ваш ответ может быть другим. Вероятно, лучше, если вы прямо проверите, что ваш вывод удовлетворяет каждому ограничению.
[(5, 3)]
3
[(7, 2), (5, 4), (11, 0)]
44
[(5, 1), (73, 4), (59, 30), (701, 53), (139, 112)]
1770977011
[(982451653, 778102454), (452930477, 133039003)]
68121500720666070
Ответы:
Mathematica,
555145Модульное обратное запрещено, но допускается возведение в модуляр. По маленькой теореме Ферма
n^(-1) % p == n^(p-2) % p
.Пример:
Просто для удовольствия:
источник
PowerMod[#2,#-2,#]
и я также не думаю, что для этой функции необходимо указывать имя, сводя ее к 48.Python 2,
165101999885 байтИспользуя маленькую теорему Ферма, как и другие ответы. Не заботится о сохранении итоговой суммы в пределах модульного диапазона, так как нас не интересует самое маленькое решение. Спасибо за изменчивость за сохранение 13 байтов.
источник
for
.x/a*b*pow(x/a,a-2,a)for a,b in l
должно сработать.Pyth,
40373629Использует маленькую теорему Ферма, благодаря алефальфе. Вычисляет, используя эту формулу .
источник
Руби, 129
Ну, товарищи, кажется, решения на Ruby должны быть длиннее, потому что модульное возведение в степень невозможно без загрузки библиотеки openssl и выполнения преобразований в OpenSSL :: BN. Тем не менее, было весело писать это:
источник
require
,eval
илиputs
.Python 2, 61
Это использует вариацию конструкции продукта, которую используют другие ответы.
Идея состоит в том, чтобы зациклить ограничения и обновить решение,
n
чтобы соответствовать текущим ограничениям, не путая предыдущие. Для этого мы отслеживаем произведениеP
простых чисел, замеченных до сих пор, и наблюдаем, что добавление кратногоP
не имеет эффекта по модулю любого уже видимого простого числа.Итак, нам просто нужно изменить,
n
чтобы удовлетворитьn%p == a
, добавив правильное кратноеP
. Мы решаем за коэффициентc
:(n + P*c) % p == a
Это требует, чтобы
c = (a-n) * P^(-1)
, где обратное взято по модулюp
. Как отмечают другие, обратная задача может быть вычислена по маленькой теореме Ферма какP^(-1) = pow(P,p-2,p)
. Таким образом,c = (a-n) * pow(P,p-2,p)
и мы обновляемn
наn+= P * (a-n) * pow(P,p-2,p)
.источник
Haskell,
68100 байтИспользование:
f [(5,1), (73,4), (59,30), (701,53), (139,112)]
->142360350966
.Редактировать: теперь с быстрой «power / mod» функцией. Старая версия (68 байт) со встроенной функцией питания:
источник