Chiński pozostająca Twierdzenie mówi nam, że zawsze możemy znaleźć numer, który produkuje wszelkie wymagane pozostałości pod różnymi głównych modułów. Twoim celem jest napisanie kodu, który wyświetli taką liczbę w czasie wielomianowym. Najkrótszy kod wygrywa.
Na przykład powiedzmy, że mamy te ograniczenia ( %
reprezentuje mod):
n % 7 == 2
n % 5 == 4
n % 11 == 0
Jednym z rozwiązań jest n=44
. Pierwsze ograniczenie jest spełnione, ponieważ 44 = 6*7 + 2
i tak 44
pozostało, 2
gdy zostanie podzielone przez 7
, i w ten sposób 44 % 7 == 2
. Pozostałe dwa ograniczenia są również spełnione. Istnieją inne rozwiązania, takie jak n=814
i n=-341
.
Wkład
Niepusta lista par (p_i,a_i)
, w której każdy moduł p_i
jest odrębną liczbą pierwszą, a każdy cel a_i
jest liczbą naturalną w zakresie 0 <= a_i < p_i
. Możesz przyjmować dane wejściowe w dowolnej dogodnej formie; to wcale nie musi być lista par. Nie możesz zakładać, że dane wejściowe są posortowane.
Wydajność
Liczba całkowita n
taka jak n % p_i == a_i
dla każdego indeksu i
. Nie musi to być najmniejsza taka wartość i może być ujemna.
Wielomianowe ograniczenie czasu
Aby zapobiec tanie rozwiązania, które po prostu spróbować n=0
, n=1
, n=2
, i tak dalej, kod musi działać w czasie wielomianowym na długości wejścia . Zauważ, że liczba m
na wejściu ma długość Θ(log m)
, więc m
sama nie jest wielomianowa w swojej długości. Oznacza to, że nie można liczyć m
ani wykonywać operacji m
, ale można obliczać operacje arytmetyczne na wartościach.
Nie można użyć nieefektywnego formatu wejściowego, takiego jak unary, aby obejść ten problem.
Inne zakazy
Wbudowane funkcje do wykonywania następujących czynności są niedozwolone: Implementuj twierdzenie Chinese Remainder, rozwiązuj równania lub liczby czynników.
Możesz używać wbudowanych funkcji do znajdowania modów i dodawania, odejmowania, mnożenia i potęgowania modularnego (z wykładnikiem liczby naturalnej). Nie możesz używać innych wbudowanych operacji modułowych, w tym odwrotności modułowej, dzielenia i ustalania kolejności.
Przypadki testowe
Dają one najmniejsze nieujemne rozwiązanie. Twoja odpowiedź może być inna. Prawdopodobnie lepiej będzie, jeśli sprawdzisz bezpośrednio, czy dane wyjście spełnia każde ograniczenie.
[(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
Odpowiedzi:
Mathematica,
555145Modułowe odwrotne jest zabronione, ale dozwolone jest potęgowanie modułowe. Przez małego twierdzenia Fermata,
n^(-1) % p == n^(p-2) % p
.Przykład:
Dla żartu:
źródło
PowerMod[#2,#-2,#]
a także nie sądzę, że jest wymagana nazwa tej funkcji, co powoduje zmniejszenie jej do 48.Python 2,
165101999885 bajtówUżywając małego twierdzenia Fermata, podobnie jak innych odpowiedzi. Nie przejmuje się utrzymywaniem końcowej sumy w zakresie modułowym, ponieważ nie interesuje nas najmniejsze rozwiązanie. Dzięki Zmienność za zaoszczędzenie 13 bajtów.
źródło
for
.x/a*b*pow(x/a,a-2,a)for a,b in l
powinno działać.Pyth,
40373629Wykorzystuje małe twierdzenie Fermata, dzięki alephalpha. Oblicza przy użyciu tej formuły .
źródło
Ruby, 129
Cóż, towarzysze, wydaje się, że rozwiązania Rubiego muszą być dłuższe, ponieważ modułowe potęgowanie nie jest dostępne bez ładowania biblioteki openssl i wykonywania konwersji do OpenSSL :: BN. Mimo to dobrze się bawiłem pisząc to:
źródło
require
,eval
lubputs
.Python 2, 61
Wykorzystuje to odmianę konstrukcji produktu, z której korzystają inne odpowiedzi.
Chodzi o to, aby ominąć ograniczenia i zaktualizować rozwiązanie tak,
n
aby spełniało obecne ograniczenie bez zepsucia poprzednich. Aby to zrobić, śledzimy iloczynP
liczb pierwszych widzianych do tej pory i obserwujemy, że dodanie wielokrotnościP
nie ma wpływu modulo na żadną już widzianą liczbę pierwszą.Tak więc musimy tylko zmienić,
n
aby spełnićn%p == a
, dodając odpowiednią wielokrotnośćP
. Rozwiązujemy dla współczynnikac
:(n + P*c) % p == a
Wymaga to
c = (a-n) * P^(-1)
, że tam gdzie odwrotność jest brana modulop
. Jak zauważają inni, odwrotność można obliczyć według Małego Twierdzenia Fermata jakoP^(-1) = pow(P,p-2,p)
. Tak więcc = (a-n) * pow(P,p-2,p)
aktualizujemyn
przezn+= P * (a-n) * pow(P,p-2,p)
.źródło
Haskell,
68100 bajtówZastosowanie:
f [(5,1), (73,4), (59,30), (701,53), (139,112)]
->142360350966
.Edycja: teraz z szybką funkcją „power / mod”. Stara wersja (68 bajtów) z wbudowaną funkcją zasilania:
źródło