470A - Последовательность хрустального шара
Как обычно, первая задача проверяет способность участника выполнять базовые арифметические действия языка и решается даже проще, чем пример — без единого цикла.
^'0- $ 1+*3*1+.
470B - Гексакосиойгексеконтагексафобия
В этой задаче используются уже более сложные структуры языка — цикл, условное выполнение и даже именованные переменные! Переменные удобно использовать в качестве счетчиков циклов и накопителей результата, чтобы не возиться со стековыми манипуляциями с той же целью. Конструкция if-then-else на FALSE выглядит следующим образом:
(true/false condition on top of stack) $ [(then statements)] ? ~ [(else statements)] ?
Код решения:
0n: {number of 6s found uninterrupted so far} 0r: {true, if 666 found} [^$ 1_=~] [ '6= $ [n; 1+ n:] ? ~ [0n:] ? n; 2 > r; | r: ] # % r; $ ["YES"] ? ~ ["NO"] ?
470C - Eval
Эту задачу можно было решать двумя способами. Можно было прочитать числа-операнды, сохранить их в именованные переменные и в зависимости от оператора применить к ним одно из действий. А можно было сделать наоборот, в зависимости от оператора сохранить нужное действие в именованную переменную (прелесть FALSE в том, что функции тоже могут быть переменными), и применить его к операндам, прочитанным в стек. Код второго способа:
[0[^ $$ 47> \58\> &]['0- \ 10*+]#] r: r;! $'+=[[+]f:]? $'-=[[-]f:]? $'*=[[*]f:]? $'/=[[/]f:]? $'%=[[\$@$@\/*-]f:]? % r;! % f;!.
470D - Шифр Цезаря
Эта задача по сути комбинирует приемы, освоенные в предыдущих: чтение длинного числа, чтение строки и операцию взятия остатка от деления, которую, впрочем, можно было заменить условным вычитанием. Код:
0[^ $$ 47> \58\> &]['0- \ 10*+]#% k: {read the key} [^$ 10=~] [ 'A- k;+ $ 25> [26-] ? 'A+ ,] #%
470E - Шахматная доска
Внезапно эта задача оказалась легче двух предыдущих. Возможно, двойной цикл for проще, чем чтение до конца строки :-)
0[^ $$ 47> \58\> &]['0- \ 10*+]#% n: [\ $ @ $ @\/*-] p: 0i: [n;i;>] [0j: [n;j;>] [j;i;+ 2p;! 11* 46 \- , j;1+j:] # " " i;1+i:] #
470F - Попарные суммы
Две следующие задачи используют новый элемент языка — оператор ø (он же O, не путать с 0), реализующий произвольный доступ на чтение к элементам стека. Для вычисления попарных сумм нужно было сначала прочитать все элементы массива в стек, а потом вычислять индексы нужных элементов, извлекать их и суммировать.
[0[^ $$ 47> \58\> &]['0- \ 10*+]#%] r: r;! n: {read the number of elements in array} 0i: [n;i;>] [r;! i;1+i:] # {read the elements of the array} 0i: [n;i;>] [$ n;O + . " " n;1-O i;1+i:] # 0i: [n;2*i;>] [% i;1+i:] #
470G - Расстояние Хэмминга
Тот же принцип, что в прошлой задаче — прочитать в стек символы двух строк (запомнив при этом длину строк в именованную переменную), затем извлекать из него пары соответствующих символов, сравнивать их и накапливать результат в еще одной именованной переменной.
0n: [^ $ 10=~] [n;1+n:] #% [^ $ 1_=~] [] #% 0i: 0d: [n;i;>] [n;i;-1- O n;n;+i;- O =~ [d;1+d:] ? i;1+i:] # 0i: [n;2*i;>] [% i;1+i:] # d;.
470H - Сортировка массива
Эту задачу, как и обычную сортировку, можно решать многими способами.
Можно написать "простейшую сортировку подсчетом", как рекомендует Egor: во внешнем цикле пройти от 1 до 100, во внутреннем — перебрать все элементы массива и вывести все элементы массива, равные счетчику внешнего цикла. Код
Можно хранить числа в именованных переменных, благо их немного, и сгенерировать код, который будет проверять пары значений переменных и менять их местами. Т.е. вместо a[0] использовать переменную a, вместо a[1] — b и т.д. Первое такое решение замечено у nab: код
Я выбрала третий вариант, не знаю, использовал ли его кто-то еще: прочитать элементы массива в стек и применить сортировку выбором, но каждый раз, когда нужно поменять местами два элемента массива, скопировать весь массив (уже с поменянными элементами) на верх стека. Через n обменов на верху стека окажется отсортированная копия массива. К сожалению, размер стека ограничен, и при размере массива ~20 элементов происходит переполнение стека. Поэтому я сильно уменьшила размер массива, что и позволило использовать другие способы решения.
[0[^ $$ 47> \58\> &]['0- \ 10*+]#%] r: r;! n: {read the number of elements in array} 0i: [n;i;>] [r;! i;1+i:] # {read the elements of the array} 1s: {# of array copies stored in memory} 0i: [n;1-i;>] [ i;m: {index of min element between i and n-1, inclusive} i;1+j: [n;j;>] [ n;m;-1- O {extract a[m]} n;j;- O {extract a[j], knowing that a[m] is on top} > [j;m:] ? {if a[j] > a[m], m := j} j;1+j: ]# i;m;=~ [ 0k: [n;k;>] [ k;e: {index of element we're extracting now} k;i;= [m;e:] ? k;m;= [i;e:] ? n;k;+e;-1- O k;1+k: ]# s;1+s: {+1 copy of array in memory} ] ? {if i != m, copy all elements, while swapping a[i] and a[m]} i;1+i:] # 0i: [n;i;>] [n;i;-1- O . " " i;1+i:] # 0i: [n;s;*i;>] [% i;1+i:] #
Хорошо что сейчас есть такие языки как c++ и java.
В 1993 году, когда был придуман этот язык, C++ уже был, а Java всего на пару лет младше. Мне кажется, автор языка придумал его не от безысходности и не в качестве основного рабочего инструмента :-)
Извините за неуместную шутку.
For problem D, I am confused by the answer checker. If you will look at My Submission here, you will see that the output matches exactly. Many other contestants had the same problem. What happened?
Probably some mix-up with end-of-line characters. You read string to be encrypted till end-of-file, but end-of-file is preceded by end-of-line, so your output probably has some invisible characters.
Я делал сортировку точно так же, только выбранный элемент на каждой итерации сразу выводил и пропускал при копировании массива.
Аналогично. А вообще, при такой логике, можно было бы периодически сохранять все элементы в переменные, отчищать стек, чтобы алгоритм работал и при больших n. Но, правда, это какое-то нубское упихивание, нежели красивое решение.
Но с другой стороны, нубским решением является расписать всю задачу через условия. Тем более, по идеи, одну из самых сложных задач.
А у меня в B вышло на два if-а меньше. 7787419
missed it :(
470H has a couple of other easier approaches than selection sort (now that I'm somewhat familiar with the language).
I wrote a bubble sort in 103B (code). The logic is pretty simple, we repeat N times (copy array, but swap top two if needed).
I also came up with a solution in 95B (code) that at most has about maybe n+3 elements on the stack, but takes O(sum(a)) instruction stack size and O(sum(a)*n) time. Again we use a bubble sort, but we temporarily hide portions of the stack (storing the values in the instruction stack) and only do swaps at the top of the stack. This was actually super easy to get right, since all of the logic was "local" (i.e. operating on the top few stack values).
That’s pretty damn awesome.
I didn't participate in the contest, but my solution was similar to what was described as the counting sort, except I didn't iterate over all possible values — instead, I found the smallest number that I haven't printed yet (in other words, it is greater than the lasts number I printed), and how many of them are in the array. Then I printed that number several times and looped. The complexity is O(n^2) and uses linear stack size. Its quite a bit longer than yours but I'm sure its possible to shorten with some tricks I see you using: 7804834
This type of contest is so interesting. O(∩_∩)O~
My solution for problem B: click :D
i had addicted to this... and wrote a simple interpreter to solve C~H besides, i thought this this resolution is better by using a placeholder and persistent insertion sort.