Китайська теорема залишків


21

Китайська теорема про залишки говорять нам , що ми завжди можемо знайти число , яке робить всі необхідні залишки при різних простих модулях. Ваша мета - написати код для виведення такої кількості в поліноміальний час. Найкоротший код виграє.

Наприклад, скажімо, що нам надаються такі обмеження ( %представляє мод):

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

Чому немає поділу?
jimmy23013

@ user23013 Немає модульного поділу, оскільки це в основному модульний зворотний.
xnor

Чи враховується матрична інверсія як розв’язування рівнянь?
дефект

@flawr: Я б так вважав.
Олексій А.

@xnor: Як ти думаєш? А як щодо функцій оптимізації?
недолік

Відповіді:


9

Математика, 55 51 45

Модульна інверсія заборонена, але дозволена модульна експоненція. За малої теореми Ферма, n^(-1) % p == n^(p-2) % p.

(PowerMod[x=1##&@@#/#,#-2,#]x).#2&@@Thread@#&

Приклад:

In[1]:= f = (PowerMod[x=1##&@@#/#,#-2,#]x).#2&@@Thread@#&;

In[2]:= f[{{5, 3}}]

Out[2]= 3

In[3]:= f[{{7, 2}, {5, 4}, {11, 0}}]

Out[3]= 1584

In[4]:= f[{{5, 1}, {73, 4}, {59, 30}, {701, 53}, {139, 112}}]

Out[4]= 142360350966

Задля розваги:

ChineseRemainder@@Reverse@Thread@#&

1
Ви можете зберегти один байт, замінивши порядок аргументів найпотаємнішої функції, таким, який ви можете використовувати, PowerMod[#2,#-2,#]і я також не думаю, що існує потреба в призначенні функції, зводячи її до 48.
Мартін Ендер,

Так, неназвані функції в порядку.
xnor

6

Пітон 2, 165 101 99 98 85 байт

Використання маленької теореми Ферма, як і інші відповіді. Не турбується збереження остаточної суми в межах модульного діапазону, оскільки нас не цікавить найменше рішення. Дякую Волатильність за збереження 13 байт.

l=input();x=reduce(lambda a,b:a*b[0],l,1)
print sum(x/a*b*pow(x/a,a-2,a)for a,b in l)

[(5, 3)]
3
[(7, 2), (5, 4), (11, 0)]
1584
[(5, 1), (73, 4), (59, 30), (701, 53), (139, 112)]
142360350966

1
Ви можете видалити пробіл раніше for.
isaacg

1
x/a*b*pow(x/a,a-2,a)for a,b in lповинні працювати.
Волатильність

Відмінна точка! Я намагався позбутися явної надмірності там, але забув, що можу просто розпакувати.
Урі Гранта

4

Піта, 40 37 36 29

M*G.^G-H2Hsm*edg/u*GhHQ1hdhdQ

Використовує маленьку теорему Ферма, завдяки алефальфі. Обчислює, використовуючи цю формулу .


3

Рубі, 129

Ну, товариші, здається, рішення Ruby повинно бути довше, оскільки модульна експоненція недоступна без завантаження бібліотеки openssl та здійснення перетворень у OpenSSL :: BN. Все-таки весело писав це:

require("openssl")
z=eval(gets)
x=1
z.map{|a,b|x*=a}
s=0
z.map{|a,b|e=a.to_bn;s+=(x/a).to_bn.mod_exp(e-2,e).to_i*b*x/a}
puts(s)

Вам не потрібні дужки при виклику require, evalабо puts.
Тутлеман

2

Пітон 2, 61

n=P=1
for p,a in input():n+=P*(a-n)*pow(P,p-2,p);P*=p
print n

Тут використовується варіант конструкції продукту, який використовують інші відповіді.

Ідея полягає у переході на обмеження та оновлення рішення 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).


1

Haskell, 68 100 байт

f l=sum[p#(m-2)*n*p|(m,n)<-l,let a#0=1;a#n=(a#div n 2)^2*a^mod n 2`mod`m;p=product(map fst l)`div`m]

Використання: f [(5,1), (73,4), (59,30), (701,53), (139,112)]-> 142360350966.

Редагувати: зараз з швидкою функцією "живлення / мод". Стара версія (68 байт) з вбудованою функцією живлення:

f l=sum[l#m^(m-2)`mod`m*n*l#m|(m,n)<-l]
l#m=product(map fst l)`div`m

Я підозрюю, що ваша реалізація power-mod не є поліномним часом, оскільки експонент виробляє величезну кількість перед модом. Ви пробували останній тестовий випадок?
xnor

@xnor: останній тестовий випадок закінчується пам'яттю через кілька секунд на моїй 2 Гб машині. Я додав швидку функцію живлення / моди.
німі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.