Załóżmy, że definiujemy macierz nieskończoną M
na N^2 -> {0, 1}
(gdzie N
zaczyna się 1
zamiast 0
) w następujący sposób:
M(1, 1)
=0
.Dla każdego
x > 1
,M(x, 1)
=1
jeślix
jest pierwsza, a0
inaczej.Dla każdego
y > 1
,M(1, y)
=y
th termin wThue-Morse sequence
.Dla każdego
x, y > 1
,M(x, y)
=M(x, y-1) + M(x-1, y) mod 2
.
16x16
Wygląda górna lewa sekcja tej macierzy (z x
wierszami i y
kolumnami):
0 1 1 0 1 0 0 1 1 0 0 1 0 1 1 0
1 0 1 1 0 0 0 1 0 0 0 1 1 0 1 1
1 1 0 1 1 1 1 0 0 0 0 1 0 0 1 0
0 1 1 0 1 0 1 1 1 1 1 0 0 0 1 1
1 0 1 1 0 0 1 0 1 0 1 1 1 1 0 1
0 0 1 0 0 0 1 1 0 0 1 0 1 0 0 1
1 1 0 0 0 0 1 0 0 0 1 1 0 0 0 1
0 1 1 1 1 1 0 0 0 0 1 0 0 0 0 1
0 1 0 1 0 1 1 1 1 1 0 0 0 0 0 1
0 1 1 0 0 1 0 1 0 1 1 1 1 1 1 0
1 0 1 1 1 0 0 1 1 0 1 0 1 0 1 1
0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 1
1 1 0 0 1 0 1 1 0 1 1 1 0 1 1 0
0 1 1 1 0 0 1 0 0 1 0 1 1 0 1 1
0 1 0 1 1 1 0 0 0 1 1 0 1 1 0 1
0 1 1 0 1 0 0 0 0 1 0 0 1 0 0 1
Twoim zadaniem jest zbudowanie programu, który oszacuje wartość dowolnego wpisu w tej macierzy tak dokładnie, jak to możliwe.
Twój program weźmie dwie liczby całkowite x
i y
jako dane wejściowe, w dowolnej formie, którą wybierzesz, i zwróci M(x, y)
, która będzie albo 0
albo 1
.
Kod może być napisany w dowolnym języku, ale nie może przekraczać 64 kilobajtów (65 536 bajtów) rozmiaru kodu źródłowego lub 2 MB (2097152 bajtów) całkowitego zużycia pamięci. Twój program musi uruchomić się z pustą pamięcią (tzn. Nie może załadować danych z innego miejsca) i działać niezależnie dla każdego wejścia (tzn. Nie może przechowywać wspólnych danych dla wielu uruchomień). Twój program musi także być w stanie ocenić wszystkie wpisy w lewym górnym rogu 8192x8192
w rozsądnym czasie.
Zwycięzcą zostanie program, który poprawnie oceni najwięcej wpisów w lewym górnym 8192 x 8192
kwadracie, a krótszy kod będzie działał jako rozstrzygający.
źródło
Odpowiedzi:
J -
4238 znakówDość szybki, 100% dokładny i dobrze w granicach pamięci.
Strategia jest następująca: będziemy obliczać kolejne antydiagonale tej macierzy, wykonując parą XOR, aby się poruszać i dodając bieżące Thue-Morse'a i bity pierwsze na końcach. Kiedy tam dotrzemy, wyciągamy wymaganą cyfrę z antyiagonalnej.
Wyjaśnienie przez wybuch:
Użycie tego czasownika dotyczy
x m y
M (x, y), jak określono w pytaniu, gdziem
jest czasownik.Aby zapisać naciśnięcia klawiszy, nie staramy się stwierdzić, czy nadal potrzebujemy więcej bitów prime lub Thue-Morse, więc obliczamy cały antypoślizgowy, aby uzyskać żądany bit. Jednak
8192 m 8192
nadal działa na mniej niż 0,07 si około 100 KiB na moim skromnym laptopie.źródło
Mathematica - 100% dokładności,
223193189 bajtówOto czytelna wersja:
Zasadniczo obliczam wstępnie wzdłuż przekątnych stałej
x+y
.Cechy:
O(x*y)
.f[8192,8192]
zajmuje około 400 sekund. Przypuszczam, że jest miejsce na ulepszenia (być możeRotateLeft
może zastąpić wewnętrzną pętlę).W
max(x,y)
pamięci wykorzystuje tylko jedną tablicę wyników do pośrednich. Dlatego nie ma potrzeby używania więcej niż około 32k (przy założeniu 32-bitowych liczb całkowitych) dla samego algorytmu (plus, cokolwiek Mathematica używa). W rzeczywistości Mathematica sama używa 31M w moim systemie, ale działa to bez problemu:źródło
O(x*y)
czasem, ale całkowity czas wykonania rośnie szybciej. Nie jestem do końca pewien, co się dzieje. Gdyby jakiś Mathematica Guru mógł mnie oświecić, która operacja w pętli nieO(1)
byłaby bardzo pomocna! :) (cóż,PrimeQ
iTotal@IntegerDigits
nie są, ale miałem je tam od samego początku, a oni tylko dzwoniliO(y)
iO(x)
razy odpowiednio)Matlab: 100% dokładności, 120 znaków, nieuzasadniony czas wykonania
Używać:
źródło
M(8192, 8192)
, nie mogę tego znieść.Python, 192 znaki
100% dokładności, oblicza M (8192,8192) w ~ 10 sekund na mojej maszynie.
źródło
Haskell - 261 bajtów - 100% - 1 MB - Nie sądzę, że wkrótce się skończy
Trwa około 10 sekund,
m 16 16
z-O2
, ale jak pisałem to i tak mogę pokazać to pomimo tego problemu:Może jakiś dobry Haskeller jest w stanie go zoptymalizować?
źródło
f p|p=not|0<1=id
powinny być lepsze. spróbuj także użyćmorse = False : concat $ iterate [True] (\a -> a ++ map not a)
dla zwiększenia lenistwa. Zastanawiam się, jak wpłynie to na wydajność.True
w golfa do0<1
iFalse
do0>1
.Perl, 137
Nie po to, żeby „wygrać” :-), ale ponieważ nie ma tu jeszcze Perla i kod został napisany, oto jest.
Wywołanie zajmuje kilka sekund
print f(8192,8192)
, przechowuje pojedynczą linię macierzy w pamięci (tablica liczb całkowitych 8192 (skalarów)), około 3,5 Mb całego procesu Perla. Próbowałem to zrobić za pomocą łańcucha zamiast tablicy (albo z wyrażeniami regularnymi, albo z dostępem do podłoża), zajmuje mniej pamięci i można grać w golfa dalej, ale działa znacznie wolniej.Zębaty:
źródło
Haskell, 223
ma to krótki czas działania (5,7 sekundy z
-O3
). pamięć nie została jeszcze sprawdzona, choć powinna być liniowa.wykorzystuje to algorytm diagonalny widoczny tutaj wcześniej.
jeśli chodzi o prędkość, jedyne, co się liczy, to algorytm diagonalny
-O3
i|foldr seq(0>1)s=0<1
osłona, która czyni listę ścisłą. wszystko inne jest implementowane raczej nieefektywnie - sprawdzanie liczby pierwotnej odbywa się poprzez sprawdzenie wszystkich mniejszych liczb do podziału, elementy sekwencji Morse'a są stale przeliczane. ale wciąż jest wystarczająco szybki :-).źródło