Обчисліть мультиноміальний коефіцієнт


27

Час ще одного легкого виклику, у якому можуть брати участь усі!

Теорема про багаточлен заявляє: Формула для обчислення n-ї потужності багаточлена

Вираз у дужках - це мультиноміальний коефіцієнт, визначений як:

Мультиноміальний коефіцієнт

Дозволення доданків k i для всіх цілих розділів n дає n -й рівень m- простого Паскаля. Ваше завдання - обчислити цей коефіцієнт.

Завдання

Напишіть програму або функцію, яка приймає m чисел, n , k 1 , k 2 , ..., k m-1 і виводить або повертає відповідний мультиноміальний коефіцієнт. За потреби ваша програма може взяти m як додатковий аргумент. Зауважте, що k m не знаходиться на вході.

  • Ці числа можуть бути введені у будь-якому форматі, який подобається, наприклад, згруповано у списки або закодовано унарним чи будь-яким іншим, якщо фактичне обчислення мультиноміального коефіцієнта виконується вашим кодом, а не процес кодування.

  • Формат виводу аналогічно гнучкий.

  • Весь код повинен працювати менше ніж за одну хвилину для n і m до 1000.

  • Не турбуйтеся про цілісне переповнення.

  • Вбудовані модулі, призначені для обчислення мультиноміального коефіцієнта, не допускаються.

  • Застосовуються стандартні лазівки.

Оцінка балів

Це код гольфу: найкоротше рішення в байтах.

Тестові справи

Input: 3, [2, 0]
Output: 3

Input: 3, [1, 1]
Output: 6

Input: 11, [1, 4, 4]
Output: 34650

Input: 4, [1,2]
Output: 12

Input: 15, [5,4,3,2]
Output: 37837800

Input: 95, [65,4,4]
Output: 1934550571913396675776550070308250

Input: 32, [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]
Output: 4015057936610313875842560000000

Input: 15, [3,3,3,3]
Output: 168168000

Input: 1000, [10,10,10,10,10,10,10,10,10,10,100,100,100,100,100,100,100,100]
Output: 1892260836114766064839886173072628322819837473493540916521650371620708316292211493005889278395285403318471457333959691477413845818795311980925098433545057962732816261282589926581281484274178579110373517415585990780259179555579119249444675675971136703240347768185200859583936041679096016595989605569764359198616300820217344233610087468418992008471158382363562679752612394898708988062100932765563185864346460326847538659268068471585720069159997090290904151003744735224635733011050421493330583941651019570222984959183118891461330718594645532241449810403071583062752945668937388999711726969103987467123014208575736645381474142475995771446030088717454857668814925642941036383273459178373839445456712918381796599882439216894107889251444932486362309407245949950539480089149687317762667940531452670088934094510294534762190299611806466111882595667632800995865129329156425174586491525505695534290243513946995156554997365435062121633281021210807821617604582625046557789259061566742237246102255343862644466345335421894369143319723958653232683916869615649006682399919540931573841920000000000000

Input: 33, [17]
Output: 1166803110

Input: 55, [28]
Output: 3824345300380220

Чи можемо ми мати помилки неточності? Тобто замість цього 1934550571913396675776550070308250ми можемо вивести 1.9345505719133966e+33?
Conor O'Brien

@ CᴏɴᴏʀO'Bʀɪᴇɴ Якщо ви використовували 64-бітні плавучі, ви взагалі не зможете представляти вхід [1000 {999 ones}], тому що показник є набагато вищим за те, що можуть представляти 64-бітні плавці. (128-бітових плавців, мабуть, буде достатньо, але я припускаю, що ви хочете використовувати власний номер JavaScript?)
Martin Ender

@ MartinBüttner Так, це правильне припущення.
Conor O'Brien

2
@quintopia "Час ще одного легкого виклику, у якому можуть брати участь усі!". Усі, крім мене! (Оскільки я поняття не маю, що симплекс і мультичор Pascals - це D :) LOL.
Ешвін Гупта

@AshwinGupta Не турбуйся про це. Ви просто обчислите вираз у другому зображенні, і вам добре піти! 👍
Кінтопія

Відповіді:


21

Желе , 7 6 байт

;_/!:/

Дивись ма, ні Unicode! Ця програма приймає єдиний список як вхідний, з n на першому індексі.

Спробуйте в Інтернеті! або перевірити всі тестові справи одразу .

Як це працює

;_/!:/ Input: A (list)

 _/    Reduce A by subtraction. This subtracts all other elements from the first.
;      Concatenate A with the result to the right.
   !   Apply factorial to all numbers in the resulting list.
    :/ Reduce the result by division. This divides the first element by the others.

Це в значній мірі алгоритм, який я мав на увазі, як найпростіший.
Кінтопія

9

CJam, 11 байт

l~_:-+:m!:/

Введіть як єдиний список із nпершим:

[95 65 4 4]

Це обробляє введення до nта m1000 майже миттєво.

Перевірте це тут.

Пояснення

l~  e# Read a line of input and evaluate it.
_   e# Duplicate.
:-  e# Fold subtraction over the list. A fold is essentially a foreach loop that starts
    e# from the second element. Hence, this subtracts all the k_i from n, giving k_m.
+   e# Append k_m to the list.
:m! e# Compute the factorial of each element in the list.
:/  e# Fold division over the list. Again, this divides n! by each of the k_i!.

Схоже, ви насправді програєте конкуренцію підрахунку байтів, але я мушу сказати, що я вражений божевільною строгістю CJam.
словосполучення

@phord Ну CJam не відповідає для Jelly (або Pyth з цього приводу). Але я був сам здивований, наскільки компактний результат закінчився. У моєму першому рішенні було 21 байт, і хоча це не здавалося оптимальним, я не думав, що зможу майже скоротити його навпіл.
Мартін Ендер

4

MATL , 21 15 байт

Давайте корисно використовувати функцію log-gamma . Це дозволяє уникнути внутрішнього переповнення, працюючи з логарифмами фабрикантів, а не з самими факторами.

1+ZgiO$Gs-h1+Zgs-ZeYo

Це працює в поточній версії (9.2.2) мови / компілятора, яка є раніше, ніж ця проблема.

Вхідні дані: спочатку число, потім числовий вектор. Результат випускається як double, що обмежує максимальний вихід десь навколо 2^52.

Приклад

>> matl 1+ZgiO$Gs-h1+Zgs-ZeYo
> 15
> [5 4 3 2]
37837800

Пояснення

1+       % implicit input (number). Add 1
Zg       % log-gamma function
i        % input (numeric vector).
0$G      % push both inputs
s-       % sum the second input (vector) and subtract from first
h1+      % append to vector. Add 1
Zg       % log-gamma function, element-wise on extended vector
s        % sum of results
-        % subtract from previous result of log-gamma
Ze       % exponential
Yo       % round. Implicit display

4
Спробуйте в Інтернеті! тепер є експериментальна підтримка MATL : matl.tryitonline.net/… Пропозиції вітаються.
Денніс

1
@Dennis Гей! Ось так сюрприз!!! Як я можу вам подякувати ?? У мене є пропозиція: якщо ви коли-небудь приїдете до Мадрида, я завдячую вам гарною вечерею та
випитими

Я дуже вдячний. Чудово мати його в Інтернеті. Як ми будемо поводитися з переглядами? Я все ще постійно оновлюю мову, знаєте ...
Луїс Мендо

Наразі я вручну оновлюю перекладачів. Якщо ви зробите оновлення, просто напишіть мене в дев'ятнадцятий байт, і я потягну його якнайшвидше. - Мені доведеться найближчим часом поїхати до Мадрида, тож я пам’ятаю вашу пропозицію. ;)
Денніс

@Dennis Чудово! Таким чином ми можемо зустрітись особисто!
Луїс Мендо

4

PowerShell, 91 74 байт

Ву! Моя 100-та відповідь на PPCG!

param($n,$k)(1..$n-join'*'|iex)/(($k|%{$n-=$_;1..$_})+(1..$n)-join'*'|iex)

Вау. Не вигравати найкоротший код, це точно. Однак, використовує кілька акуратних трюків з діапазонами. І це, мабуть, повна хитрість для тих, хто не знайомий з PowerShell.

Пояснення

Спочатку ми беремо вхід param($n,$k)і очікуємо, що $kвін буде масивом, наприклад .\compute-the-multinomial-coefficient.ps1 11 @(1,4,4).

Почнемо з чисельника (все ліворуч /). Це просто діапазон від того, 1..$nщо було -joinвідредаговано разом з, *а потім оцінено з iexметою обчислення факторіалу (тобто 1*2*3*...*$n).

Далі ми перетинаємо цикл, $k|%{...}і кожну ітерацію ми віднімаємо поточне значення $_з $n(яке нас уже не хвилює), щоб сформулювати $k_mпізніше. Крім того, ми генеруємо діапазон 1..$k_iкожної ітерації, яка залишається на конвеєрі. Ці об'єкти трубопроводу приєднуються до масиву з другим виразом, діапазоном 1..$n(який знаходиться $k_mв цій точці). Все це, нарешті, -joinредагується разом із *оцінкою iex, подібно до чисельника (це працює тому x! * y! = 1*2*3*...*x * 1*2*3*...*y, що ми не дбаємо про індивідуальне впорядкування).

Нарешті, /трапляється, чисельник ділиться на знаменник і виводить.

Правильно обробляє вихід для більшої кількості, оскільки ми не чітко викидаємо будь-які змінні, як будь-які конкретні типи даних, тому PowerShell мовчки повторно передаватиме різні типи даних під час руху за необхідності. Для більшої кількості виходи за допомогою наукових позначень найкраще зберігають значні показники, оскільки типи даних отримують повторну передачу. Наприклад, .\compute-the-multinomial-coefficient.ps1 55 @(28)буде вихід 3.82434530038022E+15. Я вважаю, що це нормально, оскільки "Вихідний формат є аналогічно гнучким" зазначено в коментарях виклику та кінтопії "Якщо кінцевий результат може вписатись у типові цілі типи, результат повинен бути точним. Якщо він не може, не обмеження того, що може бути результатом ".


Як варіант

Залежно від рішень щодо форматування виводу, наступні - 92 байти

param($n,$k)((1..$n-join'*'|iex)/(($k|%{$n-=$_;1..$_})+(1..$n)-join'*'|iex)).ToString('G17')

Що ж , як і вище, просто використовує явний висновок форматування з .ToString('G17')для досягнення необхідної кількості цифр. Для 55 @(28)цього буде вихід3824345300380220.5


Edit1 - Збережено 17 байтів, позбувшись $dта просто обчисливши його, та позбувшись обчислення $k_m, нанизуючи його разом, поки ми циклічно $k
редагуємо Edit2 - Додано альтернативну версію з явним форматуванням


3

APL (Dyalog Extended) , 9 байт

×/2!/+\⍛,

Спробуйте в Інтернеті!

Використовуючи ідею з моєї відповіді APL щодо іншого виклику, що включає багаточлени .

Мовчазна функція, лівим аргументом якої є список k, а права аргумент - n. Тестові випадки перевіряють, чи воно узгоджується з рішенням Адама із аргументами зліва та справа.

Як це працює

×/2!/+\⍛,
     +\     Cumulative sum of k's (up to m-1'th element)
       ⍛,   Append n (sum of k_1 to k_m)
  2!/       Binomial of consecutive pairs
×/          Product

(k1+k2++km)!k1!k2!km!=(k1+k2)!k1!k2!×(k1+k2++km)!(k1+k2)!k3!km!

=(k1+k2)!k1!k2!×(k1+k2+k3)!(k1+k2)!k3!×(k1+k2++km)!(k1+k2+k3)!km!

==(k1+k2k1)(k1+k2+k3k1+k2)(k1++kmk1++km1)


2

Математика, 26 байт

#!/Times@@({#-+##2,##2}!)&

Приклад:

In[1]:= #!/Times@@({#-+##2,##2}!)&[95,65,4,4]

Out[1]= 1934550571913396675776550070308250

2

Пітон 3, 93 91

Завдяки Деннісу та FryAmTheEggman .

f=lambda x:0**x or x*f(x-1)
def g(n,k):
    r=f(n)
    for i in k:r//=f(i)
    return r//f(n-sum(k))

nяк ціле, kяк ітерабельне.

Безголівки:

import functools #cache

@functools.lru_cache(maxsize=None) #cache results to speed up calculations
def factorial(x):
    if x <= 1: return 1
    else: return x * factorial(x-1)

def multinomial(n, k):
    ret = factorial(n)
    for i in k: ret //= factorial(i)
    km = n - sum(k)
    return ret//factorial(km)

1
Ви можете використовувати один пробіл замість чотирьох для динамічного біта пробілів
Conor O'Brien

Я використовував вкладки, їх замінили в цій посаді. Здається, кількість байтів у порядку. Я не впевнений у плаваючому результаті та можливому переливі.
Транг Оул

2
1. Це призводить до неправильного використання 95, [65, 4, 4]. Зауважте, що вхід не містить k_m . 2. Ви, здається, зовсім не використовуєте from functools import*.
Денніс

2
1. Ваш код для гольфу не використовується reduce. 2. import math;f=math.factorialзберігає байт. 3. Python 2 дозволив би позбутися другого /в //.
Денніс

1
Визначення fсамостійно зберігає кілька байт : f=lambda x:0**x or x*f(x-1).
FryAmTheEggman

2

APL (Dyalog Unicode) , 16 байт SBCS

Цілком заснований на математичній майстерності мого колеги Маршалла .

Функція анонімного вставки. Приймає k як правий аргумент і n як лівий аргумент.

{×/⍵!⍺-+10,⍵}

Спробуйте в Інтернеті!

{} Анонімна лямбда; лівий аргумент ( n ) і правий аргумент ( k )

0,⍵ додати нуль до k

¯1↓ відкиньте останній предмет із цього

+\ сукупна сума цього

⍺- відняти, що від n

⍵! ( k ) що

×/ продукт того


1

PARI / GP, 43 байти

Досить прямо; окрім форматування, версія, що не має волі, цілком може бути ідентичною.

m(n,v)=n!/prod(i=1,#v,v[i]!)/(n-vecsum(v))!

1

Матлаб 48 байт

Вам потрібно встановити , formatщоб longзаздалегідь , щоб отримати більш високу точність. Тоді, це досить просто:

@(n,k)factorial(n)/prod(factorial([k,n-sum(k)]))

ans(95, [65,4,4])
ans =

 1.934550571913395e+33

1

Pyth, 10 байт

/F.!MaQ-FQ

Спробуйте в Інтернеті: Демонстрація

Пояснення:

/F.!MaQ-FQ   implicit: Q = input list
       -FQ   reduce Q by subtraction
     aQ      append the result to Q
  .!M        compute the factorial for each number
/F           reduce by division

1

J, 16 байт

[(%*/)&:!],(-+/)

Використання

Для більших значень суфікс xвикористовується для позначення розширених цілих точних чисел.

   f =: [(%*/)&:!],(-+/)
   11 f 1 4 4
34650
   15x f 5 4 3 2
37837800

Пояснення

[(%*/)&:!],(-+/)  Input: n on LHS, A on RHS
             +/   Reduce A using addition
            -     Subtract that sum from n, this is the missing term
         ]        Get A
          ,       Append the missing term to A to make A'
[                 Get n
      &:!         Take the factorial of n and each value in A'
   */             Reduce using multiplication the factorials of A'
  %               Divide n! by that product and return

1

05AB1E , 8 байт

Ƹ«!R.«÷

Спробуйте в Інтернеті! Пояснення:

Æ           Subtract all the elements from the first
 ¸«         Append to the original list
   !        Take the factorial of all the elements
    R.«÷    Reduce by integer division

Я не можу знайти кращих способів виконання кроку 2 або 4.




0

Clojure, 70 байт

#(let[a apply](a /(map(fn[x](a *(map inc(range x))))(conj %(a - %)))))

Створює анонімну функцію, приймаючи всі аргументи як єдиний список, причому nперший.

30 символів "даремно" просто визначають прокляту функціональну функцію. Ну добре.


0

Perl 6 ,  52  50 байт

->\n,\k{[*](1..n)div[*] ([*] 1..$_ for |k,[-] n,|k)}

Перевірте це

->\n,\k{[*](1..n)/[*] ([*] 1..$_ for |k,[-] n,|k)}

Перевірте його (результат - Раціональний із знаменником 1)

Розширено:

->     # pointy block lambda
  \n,
  \k
{
    [*]( 1 .. n )   # factorial of 「n」

  /                 # divide (produces Rational)

    [*]             # reduce the following using &infix:«*»

      (
          [*] 1..$_ # the factorial of

        for         # each of the following

          |k,       # the values of 「k」 (slipped into list)
          [-] n,|k  # 「n」 minus the values in 「k」
      )
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.