Роздрукуйте певне значення в цій створеній двійковій матриці


14

Припустимо, ми визначаємо нескінченну матрицю Mна N^2 -> {0, 1}(де Nпочинається 1замість 0) таким чином:

  • M(1, 1)= 0.

  • Для кожного x > 1, M(x, 1)= 1якщо xє простим, 0інакше.

  • Для кожного y > 1, M(1, y)= y-го доданка в Thue-Morse sequence.

  • Для кожного x, y > 1, M(x, y)= M(x, y-1) + M(x-1, y) mod 2.

Лівий верхній 16x16розділ цієї матриці виглядає так (з xрядками та yстовпцями):

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

Ваше завдання - створити програму, яка максимально точно оцінить значення довільного запису в цій матриці.

Ваша програма буде приймати два цілі числа xі yяк вхідні дані у будь-якій обраній вами формі, і повертатиметься M(x, y), яке буде або0 або 1.

Ваш код може бути написаний будь-якою мовою, але не повинен перевищувати 64 кілобайт (65,536 байт) розміру вихідного коду або 2 МБ (2 097 152 байт) загального обсягу використання пам'яті. Ваша програма повинна починатися з порожньої пам’яті (тобто вона не може завантажувати дані з іншого місця) та запускатись незалежно для кожного вводу (тобто вона не може зберігати загальні дані для декількох запусків). Ваша програма також повинна мати можливість оцінювати всі записи у верхньому лівому куті8192x8192 квадраті за розумну кількість часу.

Програма, яка оцінює більшість записів правильно у верхньому лівому 8192 x 8192квадраті, буде переможцем, а коротший код буде виконувати функції краватки.


Я, мабуть, збираюся оновити тестовий випадок на щось трохи більш елегантне за мить, тому затримайтеся з тестуванням, поки я знову не редагую питання.
Джо З.

@mbuettner Так, це так.
Джо З.

1
Я не бачу, як нам потрібен новий тег для "точності". Це лише [виклик коду]. Будь ласка, запустіть нові ідеї жанру викликів через мета спочатку (є одне, що ми дізналися з [code trolling]).
Дверна ручка

^ Помічено. Я вилучу цей тег.
Джо З.

1
@TheDoctor Це не надто рідко. Прийнята відповідь змінюється з часом.
Джо З.

Відповіді:


9

J - 42 38 char

Досить швидкий, на 100% точний і добре в межах пам'яті.

([{+2&(~:/@#:@#@],~:/\,(p:>:)&#)0:)&<:

Стратегія полягає в наступному: ми будемо обчислювати послідовні антидіагоналі цієї матриці, виконуючи парний XOR для переміщення вздовж і додаючи поточний біт Thue-Morse та простих бітів до кінців. Потім ми витягуємо потрібну цифру з антидіагоналі, коли потрапляємо туди.

Пояснення вибухом:

(                                 )&<:  NB. decrement each of x and y
     &(                        )        NB. apply the following function...
   +                                    NB. ... (x-1)+(y-1) times...
                                0:      NB. ... starting with a zero:
    2             ~:/\                  NB.   pairwise XOR on the argument
                      ,(p:>:)&#         NB.   append prime bit (is 1+length prime?)
       ~:/@#:@#@],                      NB.   prepend TM bit (XOR of binary)
 [{                                     NB. take the x-th bit (at index x-1)

Використання цього дієслова є x m yдля M (x, y), як зазначено у питанні, де mдієслово.

   5 ([{+2&(~:/@#:@#@],~:/\,(p:>:)&#)0:)&<: 8
0
   m =: ([{+2&(~:/@#:@#@],~:/\,(p:>:)&#)0:)&<:
   1+i.16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   m/~ 1+i.16
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

Щоб зберегти натискання клавіш, ми не намагаємось сказати, чи потрібні нам ще простіші чи битві Thue-Morse, тому ми обчислюємо весь антидіагональ, щоб отримати потрібний біт. Однак 8192 m 8192на моєму скромному ноутбуці все ще працює менше ніж 0,07 с і близько 100 Кб.


6

Mathematica - 100% точність, 223 193 189 байт

f=(r=Array[0&,Max@##];For[s=2,s<=#+#2,++s,For[i=Max[1,s-#2],i<=Min[s-1,#],++i,j=s-i;r[[j]]=Which[i==1,PrimeQ@j,j==1,OddQ@Total@IntegerDigits[i-1,2],0<1,Xor@@r[[j-1;;j]]]]];If[r[[#2]],1,0])&

Ось розбірлива версія:

f[x_,y_] := (
   r = Array[0 &, Max[x,y]];
   For[s = 2, s <= x + y, ++s,
    For[
     i = Max[1, s - y],
     i <= Min[s - 1, x],
     ++i,

     j = s - i;
     r[[j]] = Which[
       i == 1,
       PrimeQ@j,
       j == 1,
       OddQ@Total@IntegerDigits[i - 1, 2],
       0 < 1,
       r[[j - 1]]~Xor~r[[j]]
       ]
     ]
    ];
   If[r[[y]], 1, 0]
   );

Я в основному розраховую по діагоналях постійних x+y.

Особливості:

  • Це точно.
  • Він працює в O(x*y).
  • f[8192,8192]займає близько 400 секунд. Я припускаю, що є місце для вдосконалення (можливо, це RotateLeftможе замінити внутрішню петлю).
  • Він використовує лише один масив до max(x,y)проміжних результатів у пам'яті. Тому немає необхідності використовувати більше ніж 32 к (при 32-бітних цілих числах) для самого алгоритму (плюс, що б Mathematica використовував). Насправді, Mathematica використовує 31M самостійно у моїй системі, але це працює без проблем:

    MemoryConstrained[f[8192, 8192], 2^21]
    

Ну, схоже, ти це отримав. Але в майбутньому я буду робити важче: P
Joe Z.

Гм, в одній із змін я, мабуть, накрутив продуктивність виконання. Внутрішній цикл все ще називається O(x*y)разів, але загальний час виконання збільшується швидше. Я не зовсім впевнений, що відбувається. Якби якийсь Mathematica Guru міг мене просвітити, яка операція в циклі не O(1)така, була б дуже корисною! :) (ну, так PrimeQі Total@IntegerDigitsнемає, але я їх мав там з самого початку, і вони лише дзвонили O(y)і O(x)раз відповідно)
Мартін Ендер

3

Matlab: 100% точність, 120 символів, необгрунтований час виконання

function z=M(x,y)
if y==1 z=(x>1)*isprime(x);elseif x==1 z=mod(sum(dec2bin(y-1)-48),2);else z=xor(M(x,y-1),M(x-1,y));end

Використовувати:

> M(4,4)
ans =
      0
> M(1, 9)
ans =
      1

1
Тепер ось питання, чи можна насправді запустити цю програму та протестувати її?
Джо З.

Якщо ти не можеш бігти M(8192, 8192), я не можу його взяти.
Джо З.

@JoeZ Це M-код, запустити його можна в Matlab або Octave.
intx13

@JoeZ Він точно обчислить M (8192, 8192). У виклику нічого не сказано про час до завершення;)
intx13

1
@JoeZ добре, схоже, що M (20,20) займає більше часу, ніж я готовий чекати. Але ей, це "точно"! : P
intx13

2

Пітон, 192 символи

100% точність, обчислює M (8192,8192) за ~ 10 секунд на моїй машині.

R=range
def M(X,Y):
 X+=1;c=[1]*X;r=[0]
 while len(r)<Y:r+=[i^1 for i in r]
 for i in R(2,X):
  if c[i]:
   for j in R(i+i,X,i):c[j]=0
  r[0]=c[i]
  for i in R(1,Y):r[i]^=r[i-1]
 return r[Y-1]

0

Haskell - 261 байт - 100% - 1MB - я не думаю, що це закінчиться незабаром

Займе близько 10 секунд m 16 16з -O2, але , як я все одно написав я можу показати його , незважаючи на цю проблему:

m x y=if n x y then 1 else 0 where n x 1=b x;n 1 y=(a!!13)!!(y-1);n x y=(n x (y-1))`f`(n(x-1)y)
f True False=True
f False True=True
f _ _=False
a=[False]:map step a where step a=a++map not a
b x=x`elem`takeWhile(<=x)e
e=c [2..]where c(p:s)=p:c[x|x<-s,x`mod`p>0]

Можливо, якийсь хороший Haskeller здатний його оптимізувати?

m' x y = if m x y then 1 else 0
    where
        m x 1 = isPrime x
        m 1 y = morse' y
        m x y = (m x (y-1)) `xor` (m (x-1) y)

xor True False = True
xor False True = True
xor _ _ = False

morse' x = (morse !! 13) !! (x-1)
morse = [False] : map step morse where step a = a ++ map not a

isPrime x = x `elem` takeWhile (<=x) primes
primes :: [Integer]
primes = sieve [2..] where sieve (p:xs) = p : sieve [x|x <- xs, x `mod` p > 0]

main = putStrLn $ show $ m' 16 16

Я думаю, що алгоритм сам по собі хибний. у будь-якому випадку, є багато речей, які ви можете зробити для цього. переважно додаткові дужки, але також f p|p=not|0<1=idповинні бути кращими. також спробуйте використовувати morse = False : concat $ iterate [True] (\a -> a ++ map not a)для посилення лінь. Цікаво, як це вплине на продуктивність.
гордий haskeller

також ви можете Trueграти в гольф 0<1і Falseдо 0>1.
гордий haskeller

0

Перл, 137

Не для 'виграшу' :-), але оскільки тут ще немає Perl, і все одно був написаний код, ось він.

sub f{($n,$m)=@_;@a=0;@a=(@a,map{0+!$_}@a)while@a<$n;for$k(2..$m){$p=0;O:{$k%$_?1:last O for 2..sqrt$k;$p=1}$p=$a[$_]^=$p for 1..$n-1}$p}

Зателефонував кілька секунд print f(8192,8192) , , зберігає в пам'яті один рядок матриці (масив з 8192 цілих чисел (скалярів)), приблизно 3,5 Мб весь процес Perl. Я намагався робити це за допомогою рядка замість масиву (або з регулярними виразами, або з доступом до субстрату), займає менше пам’яті і можна гольфу далі, але працює набагато повільніше.

Відступ:

sub f{
    ($n,$m)=@_;
    @a=0;                                  # @a will be current line.
    @a=(@a,map{0+!$_}@a)while@a<$n;        # Fill it with Thue-Morse sequence.
    for$k(2..$m){                          # Repeat until required line number.
        $p=0;                              # Find out if current line number 
        O:{                                # is a prime.
            $k%$_?1:last O for 2..sqrt$k;
            $p=1                           # Store result (0 or 1) in $p.
        }
        $p=$a[$_]^=$p for 1..$n-1          # XOR previous value in current position
    }                                      # with $p and store in $p.
    $p                                     # Return $p.
}

0

Хаскелл, 223

g n=div(filter(>=n)(iterate(*2)1)!!0)2
1%1=0>1
1%n=not$1%(n-g n)
n%1=and[rem n x>0|x<-[2..n-1]]
a%b=g[0<1]where g s|foldr seq(0>1)s=0<1|n==a+b=s!!(b-1)|0<1=g$n%1:zipWith x s(tail s)++[1%n]where n=length s+1
x p|p=not|0<1=id

це швидкий час виконання (5,7 секунди з -O3). пам'ять ще не перевірена, хоча вона повинна бути лінійною.

для цього використовується діагональний алгоритм, який бачили тут раніше.

що стосується швидкості, то єдине, що має значення, - це діагональний алгоритм -O3, і |foldr seq(0>1)s=0<1захист, який робить список суворим. все інше реалізовано досить неефективно - проста перевірка проводиться шляхом перевірки всіх менших чисел для поділу, елементи послідовності Морзе перераховуються постійно. але це все ще досить швидко :-).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.