Python, 76 73 67 bajtów
f=lambda n,k=1:1-any(a**-~k*~-a**k%n for a in range(n))or-~f(n,k+1)
Wypróbuj online!
Kolejny bajt można zapisać, zwracając wartość True zamiast 1 .
Alternatywne wdrożenie
Stosując to samo podejście, istnieje również następująca implementacja @feersum, która nie korzysta ze zrozumienia listy.
f=lambda n,k=1,a=1:a/n or(a**-~k*~-a**k%n<1)*f(n,k,a+1)or-~f(n,k+1)
Zauważ, że ta implementacja wymaga czasu O (n λ (n) ) . Wydajność można znacznie poprawić, jednocześnie zmniejszając wynik do 66 bajtów , ale funkcja zwraca wartość True dla wejścia 2 .
f=lambda n,k=1,a=1:a/n or~-a**k*a**-~k%n<1==f(n,k,a+1)or-~f(n,k+1)
tło
Definicje i zapis
Wszystkie zastosowane zmienne będą oznaczać liczby całkowite; n , k i α będą oznaczać dodatnie liczby całkowite; a p oznacza dodatnią liczbę pierwszą .
a | b jeśli b jest podzielne przez a , tj. jeśli istnieje q takie, że b = qa .
≡ b ( mod m) jeśli i b mają tę samą resztę modulo m , to znaczy, gdy M | a - b .
λ (n) jest najmniejszym k takim, że a k ≡ 1 ( mod n) - tj. takim, że n | k - 1 - dla wszystkich A , które są względnie pierwsze do n .
r (n) jest najmniejsza K tak, że 2k + 1 ≡ k + 1 ( mod n), - czyli takie, że n | a k + 1 (a k - 1) - dla wszystkich a .
λ (n) ≤ f (n)
Fix n i pozwolić na BE względnie pierwsze dla N .
Z definicji f , n | a f (n) +1 (a f (n) - 1) . Ponieważ a i n nie mają wspólnego czynnika pierwszego, nie należy również f (n) +1 i n , co oznacza, że n | a f (n) - 1 .
Ponieważ λ (n) jest najmniejszą liczbą całkowitą k taką, że n | a k - 1 dla wszystkich liczb całkowitych a, które są kopiowane do n , wynika z tego, że λ (n) ≤ f (n) .
λ (n) = f (n)
Ponieważ już ustaliliśmy nierówność λ (n) ≤ f (n) , wystarczy zweryfikować, czy k = λ (n) spełnia warunek definiujący f , tj. Że n | a λ (n) +1 (a λ (n) - 1) dla wszystkich a . W tym celu ustalimy, że p α | a λ (n) +1 (a λ (n) - 1) ilekroć p α | n .
λ (k) | λ (n) ilekroć k | n ( źródło ), więc (a λ (k) - 1) (a λ (n) -λ (k) + a λ (n) -2λ (k) + ⋯ + a λ (k) + 1) = a λ (n) - 1, a zatem a λ (k) - 1 | a λ (n) - 1 | a λ (n) +1 (a λ (n) - 1) .
Jeśli a i p α są pierwszymi, zgodnie z definicją λ i powyżej, p α | a λ (p α ) - 1 | a λ (n) +1 (a λ (n) - 1) następuje zgodnie z potrzebą.
Jeśli a = 0 , to a λ (n) +1 (a λ (n) - 1) = 0 , który jest podzielny przez wszystkie liczby całkowite.
Na koniec musimy rozważyć przypadek, w którym a i p α mają wspólny czynnik pierwszy. Ponieważ p jest liczbą pierwszą, oznacza to, że p | . Twierdzenie Carmichaela ustala, że λ (p α ) = (p - 1) p α - 1, jeśli p> 2 lub α <3 i że λ (p α ) = p α - 2 w przeciwnym razie. We wszystkich przypadkach λ (p α ) ≥ p α - 2 ≥ 2 α - 2 > α - 2 .
Dlatego λ (n) + 1 ≥ λ (p α ) + 1> α - 1 , więc λ (n) + 1 ≥ α i p α | p λ (n) +1 | a λ (n) +1 | a λ (n) +1 (a λ (n) - 1) . To kończy dowód.
Jak to działa
Podczas gdy definicje f (n) i λ (n) uwzględniają wszystkie możliwe wartości a , wystarczy przetestować te, które leżą w [0, ..., n - 1] .
Gdy wywoływane jest f (n, k) , oblicza on k + 1 (a k - 1)% n dla wszystkich wartości a w tym zakresie, czyli 0 wtedy i tylko wtedy, gdy n | a k + 1 (a k - 1) .
Jeśli wszystkie obliczone reszty są równe zero, k = λ (n) i any
zwraca False , więc f (n, k) zwraca 1 .
Z drugiej strony, podczas gdy k <λ (n) , 1-any(...)
zwróci 0 , więc f jest wywoływane rekurencyjnie z przyrostową wartością k . Wiodąca -~
zwiększa wartość zwracaną f (n, k + 1) , więc dodajemy 1 do f (n, λ (n)) = 1 raz dla każdej liczby całkowitej w [1, ..., λ (n) - 1 ] . Ostateczny wynik to zatem λ (n) .