В subfactorial или Rencontres номер ( A000166 ) представляет собой последовательность чисел , подобных факторным числа , которые показывают в комбинаторике перестановок. В частности, n- й субфакториал ! N дает количество нарушений для набора из n элементов. Нарушение - это перестановка, в которой ни один элемент не остается в том же положении. Субфакториал может быть определен через следующее отношение повторения:
!n = (n-1) (!(n-1) + !(n-2))
Фактически, то же самое рекуррентное отношение верно для факториала, но для субфакториала мы начинаем с:
!0 = 1
!1 = 0
(Для факториала у нас, конечно, 1! = 1. )
Ваша задача - вычислить ! N , учитывая n .
правила
Как и факториал, субфакториал растет очень быстро. Хорошо, если ваша программа может обрабатывать только входные данные n , так что ! N может быть представлен типом номера вашего языка. Тем не менее, ваш алгоритм теоретически должен работать для произвольного n . Это означает, что вы можете предполагать, что интегральные результаты и промежуточные значения могут быть представлены именно вашим языком. Обратите внимание, что это исключает постоянную e, если она хранится или вычисляется с конечной точностью.
Результат должен быть точным целым числом (в частности, вы не можете приблизить результат с научной нотацией).
Вы можете написать программу или функцию и использовать любой из стандартных методов получения ввода и предоставления вывода.
Вы можете использовать любой язык программирования , но учтите, что эти лазейки по умолчанию запрещены.
Это код-гольф , поэтому самый короткий действительный ответ - измеренный в байтах - выигрывает.
Тестовые случаи
n !n
0 1
1 0
2 1
3 2
4 9
5 44
6 265
10 1334961
12 176214841
13 2290792932
14 32071101049
20 895014631192902121
21 18795307255050944540
100 34332795984163804765195977526776142032365783805375784983543400282685180793327632432791396429850988990237345920155783984828001486412574060553756854137069878601
источник
Ответы:
Funciton , 336 байт
Число байтов предполагает кодировку UTF-16 с BOM.
Это определяет функцию,
f
которая принимает одно целое число и выводит другое целое число при повороте на 90 градусов влево. Это работает для произвольно больших входов.Попробуйте онлайн!
Учитывая, что это Funciton, он даже достаточно быстрый (n = 20 занимает около 14 секунд на TIO). Основное замедление происходит из-за двойной рекурсии, поскольку я не думаю, что интерпретатор Funciton автоматически запоминает функции.
К сожалению, некоторые моноширинные шрифты неправильно моноширируют
♭
и / или не вставляют небольшие пропуски между строками. Вот скриншот кода от TIO во всей его красе:Я думаю, что можно было бы еще немного поиграть в это, например, изменив условие с
>0
на<1
и поменяв местами условные ветви, чтобы я мог повторно использовать числовой литерал, или, возможно, используя совершенно другую формулу, но я вполне доволен тем, насколько он компактен.объяснение
Это в основном реализует рекурсию, данную в вызове, хотя и использует базовый вариант ! (- 1) =! 0 = 1 . n-1 и n-2 вычисляются с помощью функции-предшественника
♭
, а промежуточный результат n-1 повторно используется в трех местах. В этом нет ничего особенного, поэтому я просто быстро пройду поток управления:Это заголовок функции, который выдает вход функции n по присоединенной строке. Это немедленно достигает T-перехода, который просто дублирует значение.
0
Окно просто числовой литерал. Четырехсторонний переход вычисляет две функции: путь, ведущий снизу, вычисляет 0 <n , который мы будем использовать для определения базового варианта. Путь, идущий влево отдельно, вычисляет 0 << n (сдвиг влево), но мы отбрасываем это значение с помощью конструкции Старкова .Мы приведем это в трехстороннее условное
?
. Если значение равно false, мы возвращаем постоянный результат1
. Свободный конец справа от?
выхода функции. Здесь я поворачиваю его на 180 градусов, чтобы относительная ориентация ввода и вывода былаf
более удобной в остальной части программы.Если условие было выполнено, то будет использоваться другое значение. Давайте посмотрим на путь, который ведет к этой ветви. (Обратите внимание, что оценка Funciton на самом деле ленива, так что эта ветвь никогда не будет оцениваться, если она не нужна, что делает рекурсию возможной в первую очередь.)
В другой ветви мы сначала вычисляем n-1, а затем дважды разделяем путь, чтобы получить три копии значения (одну для коэффициента повторения, одну для первого субфакториала, последнюю для n-2 ).
Как я уже сказал, мы снова уменьшаем одну копию другой
♭
, затем рекурсивно подаем n-1 и n-2f
и, наконец, добавляем два результата вместе в+
.Осталось только умножить n-1 на ! (N-1) +! (N-2) .
источник
Оазис , 5 байт
Использует формулу, данную Мартином. Код:
Разобранная версия:
с
a(0) = 1
иa(1) = 0
.Объяснение
a(n) =
:Попробуйте онлайн!
источник
X
:-) Кстати, вы уже реализовали это ? На днях мы не сможем сойти с рук, просто изменив начальные значенияHaskell , 25 байт
Попробуйте онлайн! Использует другое повторение со страницы OEIS .
источник
Желе , 7 байт
Такой подход создает недостатки, поэтому он довольно медленный.
Попробуйте онлайн!
Как это работает
источник
Брахилог (2), 11 байт
Попробуйте онлайн!
объяснение
По сути, это всего лишь прямой перевод спецификации с английского языка на брахилог (и, следовательно, имеет то преимущество, что его можно легко модифицировать для обработки небольших изменений в спецификации, таких как поиск количества отклонений в конкретном списке).
источник
Языки со встроенными решениями
Следуя предложению xnor, это ответ CW, в котором должны быть отредактированы тривиальные решения, основанные на единственном встроенном для вычисления субфакториала или генерации всех неисправностей.
Mathematica, 12 байт
источник
Python 3 ,
3532 байтаПри этом используется рекуррентное соотношение ! N = n! (N-1) + (-1) n из ответа @ Laikoni's Haskell с базовым регистром ! 0 = 1 .
Попробуйте онлайн!
источник
f=lambda n:n<1or n*f(n-1)+(-1)**n
.n=-1
, совершенно не имеет значения, какое значение вы используете. Это может быть полезно для некоторых языков (например, в Mathematica вы можете оставить его неопределенным, если это сохранит какие-либо байты).М , 9 байт
Как вы можете видеть, удалив
Ḟ
, M использует символическую математику, поэтому проблем с точностью не будет.Попробуйте онлайн! Не самое короткое решение, которое было опубликовано, но быстро .
Как это работает
источник
MATL ,
98 байтАналогично ответу желе @Dennis ' , это на самом деле создает перестановки и подсчитывает, сколько из них являются отклонениями; так медленно
Попробуйте онлайн!
источник
Математика , 21 байт
Я очень новичок в этом и понятия не имею, что я делаю ...
Попробуйте онлайн!
источник
Round[(#/. 0->2)!/E]&
и±0=1;±n_:=Round[n!/E]
(хотя я не знаю, поддерживает ли Mathics однобайтовые кодировки для исходных файлов, как это делает Mathematica).±
во втором. Это будет работать сf
, но за счет двух байтов.Round[#!/E]+1-Sign@#&
. Раздражающие начальные значения ...!Рубин, 27 байт
~0**n
короче чем(-1)**n
!источник
CJam (10 байт)
Демо онлайн .
При этом используется повторение
!n = n !(n-1) + (-1)^n
, которое я получил,n! / e
а затем обнаружил, что оно уже было в OEIS.рассечение
Цикл вычисляет
(-1)^n !n
, поэтому нам нужно взять абсолютное значение в конце:источник
05AB1E , 8 байтов
Попробуйте онлайн!
объяснение
источник
MATLAB, 33 байта
Функция Anonympus, которая использует формулу в Разделе 3 « Нарушения и приложения» » Мехди Хассани.
Пример использования:
источник
JavaScript (ES6), 26 байт
Использует рекуррентное соотношение из ответа @ Laikoni. В ES7 вы можете сохранить байт, используя
+(-1)**n
вместо-(~n%2|1)
.источник
PostScript,
817669 байтВот реализации обеих формул.
п * е (п-1) + (- 1) ^ п
/ f {dup 0 eq {pop 1} {dup dup 1 sub f mul exch 2 mod 2 mul 1 sub sub} ifelse} defЭта версия выводит число с плавающей точкой. Если необходимо вывести целое число:
который весит 73 байта.
Другая формула немного длиннее: 81 байт.
(П-1) * (е (п-1) + F (п-2))
Эти функции получают свои аргументы из стека и оставляют результат в стеке.
Вы можете проверить функции в файле или в интерактивном приглашении PostScript (например, GhostScript) с помощью
выход
Вот полный файл PostScript, который отображает вывод на экран или страницу принтера. (Комментарии в PostScript начинаются с
%
).источник
-1 3 2 roll exp
немного корочеexch 2 mod 2 mul 1 sub
.exp
: oops: Однако, он возвращает число с плавающей запятой, и я думаю, что мне нужно вывести целое число, чтобы соответствовать вопросу.cvi
и сделать экономию. (Примечание: не проверено, но, читая документ, я думаю, что это должно работать).cvi
работает, и все еще короче, чем моя предыдущая версия.PHP, 69 байт
использовать этот способ
a(n) = n*a(n-1) + (-1)^n
источник
PHP,
5044Бежать с
echo <n> | php -nR '<code>
Прелесть в
a(n) = n*a(n-1) + (-1)^n
том, что это зависит только от предыдущего значения. Это позволяет реализовать его итеративно, а не рекурсивно. Это экономит долго функцию декларации.-6 байт @Titus. Благодарность !
источник
$i++<$argv[1]
. -2 байт:for(;$i++<$argv[1];)$n=++$n*$i-$i%2*2;echo$n+1;
. (-3 байта с-R
и$argn
.)-R
а$argn
?Mathematica, 40 байт
Который входит в 31 байт в кодировке по умолчанию ISO 8859-1.
источник
C, 34 байта
Объяснение:
источник
R, 47 байт
Использует ту же формулу, что и ответ Мего .
Альтернативный метод, 52 байта с использованием
PerMallows
библиотекиисточник
На самом деле , 18 байт
Попробуйте онлайн!
Объяснение:
12-байтовая версия, которая работала бы, если бы на самом деле имела большую точность:
Попробуйте онлайн!
В отличие от всех других ответов (на момент публикации), это решение не использует ни рекурсивную формулу, ни формулу суммирования. Вместо этого он использует следующую формулу:
Эту формулу относительно легко реализовать на самом деле:
Теперь единственная проблема в том, что формула верна только для положительного
n
. Если вы попытаетесь использоватьn = 0
, формула неверно дает0
. Однако это легко исправить: применяя логическое отрицание к входу и добавляя его к выходу формулы, правильный вывод дается для всех неотрицательных значенийn
. Таким образом, программа с этой коррекцией:источник
n = 100
)(-1)**n/n!
не может быть представлено с плавающей точкой двойной точности IEEE 754. Это приемлемо в соответствии с проблемой.n=4
...С накоплением , 30 байтов
Попробуйте онлайн!
Простая рекурсивная функция. Использует тот факт, что
!n = not n
дляn < 2
. Звоните какn f
.источник
Алиса ,
2018 байтПопробуйте онлайн!
объяснение
При этом используется рекурсия от Laikoni отвечают , ! П = п! (П-1) + (-1) п . Как и в ответе Funciton, я использую базовый вариант ! (- 1) = 1 . Мы помещаем это 1 в стек с
1.
. Тогда это ...... это просто обычный десятичный каркас ввода / вывода. Основной код на самом деле
Сломано:
источник