Oblicz współczynnik wielomianowy

27

Czas na kolejne łatwe wyzwanie, w którym wszyscy mogą wziąć udział!

Twierdzenie o wielomianach stwierdza: Wzór na obliczenie n-tej potęgi wielomianu

Wyrażenie w nawiasach to współczynnik wielomianowy, zdefiniowany jako:

Współczynnik wielomianowy

Dopuszczenie, aby terminy k i obejmowały wszystkie partycje całkowite n, daje n -ty poziom m -simplex Pascala. Twoim zadaniem jest obliczenie tego współczynnika.

Zadanie

Napisz program lub funkcję, która pobierze m liczb, n , k 1 , k 2 , ..., k m-1 , i wyświetli lub zwróci odpowiedni współczynnik wielomianowy. Twój program może opcjonalnie wziąć m jako dodatkowy argument, jeśli zajdzie taka potrzeba. Zauważ, że k m nie znajduje się na wejściu.

  • Liczby te mogą być wprowadzane w dowolnym formacie, który nam się podoba, na przykład pogrupowane w listy lub zakodowane jako jednoargumentowe lub cokolwiek innego, o ile kod oblicza rzeczywiste obliczenie współczynnika wielomianowego, a nie proces kodowania.

  • Format wyjściowy jest podobnie elastyczny.

  • Cały kod powinien działać w ciągu mniej niż jednej minuty n i m do 1000.

  • Nie przejmuj się przepełnieniem liczb całkowitych.

  • Wbudowane funkcje obliczania współczynnika wielomianowego są niedozwolone.

  • Obowiązują standardowe luki.

Punktacja

To jest kod golfowy: wygrywa najkrótsze rozwiązanie w bajtach.

Przypadki testowe

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
kwintopia
źródło
Czy możemy mieć błędy niedokładności? Czy zamiast tego 1934550571913396675776550070308250możemy wydać dane wyjściowe 1.9345505719133966e+33?
Conor O'Brien
@ CᴏɴᴏʀO'Bʀɪᴇɴ Jeśli używałeś pływaków 64-bitowych, w ogóle nie będziesz w stanie reprezentować danych wejściowych [1000 {999 ones}], ponieważ wykładnik wykracza daleko poza to, co mogą reprezentować pływaki 64-bitowe. (Prawdopodobnie 128-bitowe zmiennoprzecinkowe wystarczą, ale zakładam, że chcesz użyć rodzimego typu kodu JavaScript?)
Martin Ender
@ MartinBüttner Tak, to prawidłowe założenie.
Conor O'Brien
2
@quintopia „Czas na kolejne łatwe wyzwanie, w którym wszyscy mogą wziąć udział!”. Wszyscy oprócz mnie! (Ponieważ nie mam pojęcia, jakie są jednokierunkowe i wielomianowe Pascals D :) LOL.
Ashwin Gupta
@AshwinGupta Nie martw się tym. Po prostu obliczasz wyrażenie na drugim obrazku i możesz zacząć! 👍
kwintopia

Odpowiedzi:

21

Galaretka , 7 6 bajtów

;_/!:/

Spójrz, nie ma Unicode! Ten program przyjmuje pojedynczą listę jako dane wejściowe, gdzie n ma swój pierwszy indeks.

Wypróbuj online! lub zweryfikuj wszystkie przypadki testowe jednocześnie .

Jak to działa

;_/!:/ 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.
Dennis
źródło
Jest to właściwie algorytm, który miałem na myśli jako najprostszy.
quintopia
9

CJam, 11 bajtów

l~_:-+:m!:/

Wprowadź jako pojedynczą listę z npierwszym:

[95 65 4 4]

To obsługuje dane wejściowe do 1000 ni mprawie natychmiast.

Sprawdź to tutaj.

Wyjaśnienie

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!.
Martin Ender
źródło
Wygląda na to, że faktycznie przegrasz konkurencję liczenia bajtów, ale muszę przyznać, że jestem pod wrażeniem szalonej zwięzłości CJam.
phord
@phord Well CJam nie może się równać z Jelly (lub Pyth w tej kwestii). Ale sam byłem zaskoczony, jak bardzo się skończyło. Moje pierwsze rozwiązanie miało 21 bajtów i chociaż nie wydawało się optymalne, nie sądziłem, że mógłbym prawie przeciąć to na pół.
Martin Ender
4

MATL , 21 15 bajtów

Postawmy funkcję log-gamma do dobrego wykorzystania. Pozwala to uniknąć wewnętrznego przepełnienia poprzez pracę z logarytmami silni, a nie z samymi silnikami.

1+ZgiO$Gs-h1+Zgs-ZeYo

Działa to w bieżącej wersji (9.2.2) języka / kompilatora, która jest wcześniejsza niż to wyzwanie.

Wejściami są: najpierw liczba, a następnie wektor numeryczny. Wynik jest wytwarzany jako a double, co ogranicza maksymalną moc wyjściową do około 2^52.

Przykład

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

Wyjaśnienie

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
Luis Mendo
źródło
4
Wypróbuj online! teraz ma eksperymentalną obsługę MATL : matl.tryitonline.net/… Sugestie są mile widziane.
Dennis
1
@Dennis Hej! Co za niespodzianka!!! Jak mogę ci podziękować?? Mam sugestię: jeśli kiedykolwiek przyjedziesz do Madrytu, jestem ci winien dobry obiad i drinki
Luis Mendo
Jestem naprawdę wdzięczna. Wspaniale jest mieć go online. Jak będziemy obsługiwać zmiany? Ciągle aktualizuję język, wiesz ...
Luis Mendo
Na razie ręcznie aktualizuję tłumaczy. Jeśli zrobisz aktualizację, po prostu pinguj mnie w Dziewiętnastym bajcie, a ja wyciągnę ją jak najszybciej. - W najbliższej przyszłości będę musiał jechać do Madrytu, więc będę pamiętać o twojej ofercie. ;)
Dennis
@Dennis Świetnie! W ten sposób możemy się spotkać osobiście!
Luis Mendo,
4

PowerShell, 91 74 bajtów

Zabiegać! Moja setna odpowiedź na PPCG!

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

Uff Na pewno nie wygrasz najkrótszego kodu. Wykorzystuje kilka schludnych sztuczek z zasięgami. I jest to prawdopodobnie kompletny bełkot dla każdego, kto nie zna PowerShell.

Wyjaśnienie

Najpierw bierzemy dane wejściowe param($n,$k)i oczekujemy, $kże będziemy tablicą, np .\compute-the-multinomial-coefficient.ps1 11 @(1,4,4).

Zaczniemy od licznika (wszystko po lewej stronie /). Jest to po prostu zakres od 1..$ntego, który został -joinedytowany razem, *a następnie oceniany za pomocą iexdo obliczenia silni (tj 1*2*3*...*$n.).

Następnie, pętla nad $k|%{...}i każda iteracja odejmujemy aktualną wartość $_z $n(które już nie obchodzi o) formułowanie $k_mpóźniej. Dodatkowo generujemy zakres 1..$k_ikażdej iteracji, który zostaje w potoku. Te obiekty potoku zostają połączone w tablicę z drugim wyrażeniem - zakresem 1..$n(który jest $k_mw tym momencie). Wszystko to jest ostatecznie -joinedytowane razem *i oceniane za pomocą iex, podobnie jak licznik (działa to x! * y! = 1*2*3*...*x * 1*2*3*...*y, ponieważ nie dbamy o indywidualne zamawianie).

Wreszcie, /zdarza się, licznik jest dzielony przez mianownik i dane wyjściowe.

Obsługuje dane wyjściowe poprawnie dla większych liczb, ponieważ nie przesyłamy jawnie żadnych zmiennych jako poszczególnych typów danych, więc PowerShell po cichu przerzuci w razie potrzeby różne typy danych w locie. W przypadku większych liczb dane wyjściowe za pomocą notacji naukowej mają najlepiej zachować znaczące liczby w miarę ponownego przesyłania typów danych. Na przykład .\compute-the-multinomial-coefficient.ps1 55 @(28)wyświetli 3.82434530038022E+15. Zakładam, że jest to OK, biorąc pod uwagę, że „Format wyjściowy jest podobnie elastyczny” jest określony w komentarzach i komentarzach kwintopii „Jeśli końcowy wynik może mieścić się w natywnie obsługiwanych typach liczb całkowitych, wynik musi być dokładny. Jeśli nie, nie ma ograniczeń co do wyniku. ”


Alternatywnie

W zależności od decyzji o formatowaniu danych wyjściowych następujące po 92 bajtach

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

Który jest taki sam jak powyżej, po prostu używa jawnego formatowania wyjściowego za pomocą, .ToString('G17')aby osiągnąć pożądaną liczbę cyfr. Do 55 @(28)tego wyjdzie3824345300380220.5


Edycja1 - Zapisano 17 bajtów, pozbywając się $di obliczając bezpośrednio, a pozbywając się obliczeń $k_m, ciągnąc je podczas pętli $k
Edytuj2 - Dodano alternatywną wersję z jawnym formatowaniem

AdmBorkBork
źródło
3

APL (Dyalog Extended) , 9 bajtów

×/2!/+\⍛,

Wypróbuj online!

Wykorzystując pomysł z mojej odpowiedzi APL na inne wyzwanie, które dotyczy wielomianów .

Milcząca funkcja, której lewy argument jest listą k, a prawy argument to n. Przypadki testowe sprawdzają, czy zgadzają się z rozwiązaniem Adama, z odrzuconymi lewymi i prawymi argumentami.

Jak to działa

×/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)

Bubbler
źródło
2

Mathematica, 26 bajtów

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

Przykład:

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

Out[1]= 1934550571913396675776550070308250
alephalpha
źródło
2

Python 3, 93 91

Dzięki Dennis i 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))

njako liczba całkowita, kjak iterowalna.

Nie golfowany:

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)
Trang Oul
źródło
1
Możesz użyć pojedynczej spacji zamiast czterech dla dynamicznego bitu białych znaków
Conor O'Brien
Użyłem kart, zostały zastąpione w tym poście. Liczba bajtów wydaje się być OK. Nie jestem pewien co do wyniku zmiennoprzecinkowego i możliwego przepełnienia.
Trang Oul
2
1. To powoduje niepoprawne dla 95, [65, 4, 4]. Zauważ, że dane wejściowe nie zawierają k_m . 2. Wydaje się, że wcale nie używasz from functools import*.
Dennis
2
1. Twój kod do gry w golfa nie jest używany reduce. 2. import math;f=math.factorialzapisuje bajt. 3. Python 2 pozwoli Ci pozbyć się sekundę /w //.
Dennis
1
Definiowanie fna własną rękę oszczędza kilka bajtów : f=lambda x:0**x or x*f(x-1).
FryAmTheEggman
2

APL (Dyalog Unicode) , 16 bajtów SBCS

Całkowicie oparty na matematycznych umiejętnościach mojego kolegi Marshalla .

Anonimowa funkcja poprawki. Przyjmuje k jako prawy argument, a n jako lewy argument.

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

Wypróbuj online!

{} Anonimowa lambda; jest lewym argumentem ( n ) i jest prawym argumentem ( k )

0,⍵ dodaj zero do k

¯1↓ upuść z tego ostatni element

+\ łączna suma tego

⍺- odejmij to od n

⍵! ( k ) to

×/ produkt tego

Adám
źródło
1

PARI / GP, 43 bajty

Całkiem proste; oprócz formatowania wersja bez golfa może być identyczna.

m(n,v)=n!/prod(i=1,#v,v[i]!)/(n-vecsum(v))!
Charles
źródło
1

Matlab 48 bajtów

Trzeba ustawić format, aby longz wyprzedzeniem, aby uzyskać większą precyzję. Zatem jest to całkiem proste:

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

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

 1.934550571913395e+33
Brainkz
źródło
1

Pyth, 10 bajtów

/F.!MaQ-FQ

Wypróbuj online: demonstracja

Wyjaśnienie:

/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
Jakube
źródło
1

J, 16 bajtów

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

Stosowanie

W przypadku większych wartości sufiks xjest używany do oznaczania liczb całkowitych o rozszerzonej precyzji.

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

Wyjaśnienie

[(%*/)&:!],(-+/)  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
mile
źródło
1

05AB1E , 8 bajtów

Ƹ«!R.«÷

Wypróbuj online! Wyjaśnienie:

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

Nie mogę znaleźć lepszych sposobów wykonania kroku 2 lub 4.

Neil
źródło
0

Clojure, 70 bajtów

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

Tworzy anonimową funkcję, biorąc wszystkie argumenty jako jedną listę, z npierwszym.

30 znaków jest „zmarnowanych”, co definiuje cholerną funkcję silni. No cóż.

MattPutnam
źródło
0

Perl 6 ,  52  50 bajtów

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

Sprawdź to

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

Przetestuj (wynik jest wymierny o mianowniku 1)

Rozszerzony:

->     # 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」
      )
}
Brad Gilbert b2gills
źródło