Multinom katsayısını hesapla


27

Herkesin katılabileceği başka bir kolay mücadele zamanı!

Multinom teoremi şöyle diyor: Formula for computing the nth power of a multinomial

Parantez içindeki ifade, multinom katsayısıdır, şöyle tanımlanır:

Multinomial coefficient

Terimleri izin k i her tamsayı bölümleri yoluyla aralığı için n verir n Pascal ait ıncı seviyesini m -simplex. Görevin bu katsayısı hesaplamak.

Görev

M sayılarını alan, n , k 1 , k 2 , ..., k m-1 alan ve karşılık gelen çok terimsel katsayısı veren veya veren bir program veya işlev yazın . Programınız isteğe bağlı olarak gerekirse ek bir argüman olarak m alabilir . Bunu not et k m girişinde değil.

  • Bu sayılar, örneğin listelerde gruplandırılmış veya tekdüze olarak kodlanmış, herhangi bir biçimde girilebilir, ya da multinom katsayısının gerçek hesaplaması kodunuz tarafından gerçekleştirildiği sürece kodunuz tarafından gerçekleştirilebilir.

  • Çıkış formatı benzer şekilde esnektir.

  • Tüm kodlar bir dakikadan daha az bir sürede n ve m 'den 1000' e kadar çalışmalıdır.

  • Tamsayı taşması konusunda endişelenmeyin.

  • Multinom katsayısını hesaplamak için tasarlanan yerleşik yapılara izin verilmez.

  • Standart boşluklar uygulanır.

puanlama

Bu kod golf: Bayt cinsinden en kısa çözüm kazanır.

Test durumları

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

Hatalı hatalar yapabilir miyiz? Yani bunun yerine 1934550571913396675776550070308250çıktı alabilir miyiz 1.9345505719133966e+33?
Conor O'Brien,

@ CᴏɴᴏʀO'Bʀɪᴇɴ Eğer 64 bitlik yüzdürme kullandıysanız, üstelik girdiyi temsil edemezsiniz [1000 {999 ones}], çünkü üs, 64 bitlik yüzdürmelerin temsil edebileceğinden çok daha fazladır. (128 bitlik yüzmeler muhtemelen yeterli olacaktır, ancak JavaScript’in yerel sayı türünü kullanmak istediğinizi farz ediyorum?)
Martin Ender

@ MartinBüttner Evet, doğru bir varsayım bu.
Conor O'Brien,

2
@quintopia "Herkesin katılabileceği bir başka kolay meydan okuma zamanı!". Benden başka herkes! (Pascals simpleks ve multinomların ne olduğu hakkında hiçbir fikrim olmadığı için D :) LOL.
Ashwin Gupta

@ AshwinGupta Endişelenme. Siz sadece ikinci görüntüdeki ifadeyi hesaplarsınız ve gitmeniz iyi olur! 👍
quintopia,

Yanıtlar:


21

Jöle , 7 6 bayt

;_/!:/

Bak ma, Unicode yok! Bu program , ilk indeksinde n olan tek bir listeyi giriş olarak alır .

Çevrimiçi deneyin! veya tüm test durumlarını bir kerede doğrulayın .

Nasıl çalışır

;_/!:/ 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.

Bu oldukça basit olduğunu düşündüğüm algoritma.
quintopia,

9

CJam, 11 bayt

l~_:-+:m!:/

nİlk önce tek bir liste olarak giriş yapın :

[95 65 4 4]

Bu saplar kadar girer nve mhemen hemen anında 1.000.

Burada test et.

açıklama

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!.

Bayt sayma yarışmasını gerçekten kaybedeceksiniz gibi gözüküyor, ama şunu söylemeliyim ki CJam'ın çılgınlıklarından etkilendim.
pford

@phord Well CJam Jelly ile eşleşmiyor (veya bu konu için Pyth). Ama ne kadar kompakt sonuçlandığına kendime oldukça şaşırdım. İlk çözümümde 21 bayt vardı ve en uygun gibi görünmese de, bunu neredeyse yarıya indirebileceğimi düşünmedim.
Martin Ender

4

Matl , 21 15 bayt

Diyelim koymak log-gama fonksiyonunu iyi kullanmak. Bu, factoriallerin kendi logaritmalarıyla değil, factoriallerin logaritmalarıyla çalışarak iç taşmaları önlenir.

1+ZgiO$Gs-h1+Zgs-ZeYo

Bu , bu zorluktan önceki dil / derleyicinin geçerli sürümünde (9.2.2) çalışır .

Girişler: önce sayı, sonra sayısal vektör. Sonuç, doubleetrafındaki herhangi bir yere maksimum çıktıyı sınırlayan a olarak üretilir 2^52.

Örnek

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

açıklama

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
Çevrimiçi deneyin! Şimdi deneysel MATL desteği var: matl.tryitonline.net/… Önerilerinizi bekliyoruz.
Dennis

1
@Dennis Hey! Bu ne sürpriz!!! Nasıl teşekkür edebilirim?? Bir önerim var: Madrid'e gelirseniz size iyi bir akşam yemeği ve bir şeyler
içeceğim

Gerçekten minnettarım. Çevrimiçi olması harika. Revizyonları nasıl halledeceğiz? Ben hala sürekli dili güncelliyorum, biliyorsunuz ...
Luis Mendo

Şimdilik tercümanları manuel olarak güncelliyorum. Bir güncelleme yaparsanız, sadece On Dokuzuncu Bayt'ta bana ping atın ve ben en kısa zamanda çekeceğim. - Yakın gelecekte Madrid'e gitmek zorunda kalacağım, bu yüzden teklifinizi aklımda tutacağım. ;)
Dennis,

@Dennis Harika! Bu şekilde şahsen tanışabiliriz!
Luis Mendo,

4

PowerShell, 91 74 bayt

Woo! PPCG'ye 100. cevabım!

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

Whew. En kısa kodu kazanamayacaksınız, orası kesin. Ancak, aralıkları ile birkaç temiz hileler kullanır. Ve bu muhtemelen PowerShell'e aşina olmayan kimselere tamamen saçmalıktır.

açıklama

Öncelikle girdi alıyoruz param($n,$k)ve $kbir dizi olmasını bekliyoruz , örn .\compute-the-multinomial-coefficient.ps1 11 @(1,4,4).

Pay ile başlayacağız (soldaki her şey /). Bu, sadece bir aralık var 1..$nolduğu edilmiştir -joinbirlikte ed *ve daha sonra değerlendirildi iexfaktör hesaplamak için (diğer bir deyişle, 1*2*3*...*$n).

Sonra, üzerinde biz döngü $k|%{...}ve biz şimdiki değeri çıkarın her yineleme $_dan $n(yaklaşık artık umurumda değil) formüle etmek $k_mdaha sonra. Ek olarak, 1..$k_iboru hattında kalan her yinelemenin aralığını üretiyoruz . Bu boru hattı nesneleri, 1..$n( $k_mbu noktada olan) aralık olan ikinci ifadeyle dizi birleştirilir . Bunların hepsi nihayet -joinbirlikte *değerlendirilir ve birlikte değerlendirilir.iex (çünkü bu eserler payında benzer, x! * y! = 1*2*3*...*x * 1*2*3*...*ybireysel sipariş umurumda değil bu yüzden).

Sonunda, / olur, payda payda ile bölünür ve çıktı.

Herhangi bir değişkeni belirli bir veri türü olarak açıkça yayınlamadığımız için çıktıyı daha büyük sayılar için doğru şekilde işler, böylece PowerShell sessizce gerektiği gibi anında farklı veri türleri olarak yeniden yayınlanır. Daha büyük sayılar için, veri tipleri yeniden oluşturulurken önemli rakamları en iyi şekilde korumak için bilimsel gösterim yoluyla çıktılar. Örneğin, .\compute-the-multinomial-coefficient.ps1 55 @(28)çıkacak 3.82434530038022E+15. “Çıktı formatı benzer şekilde esnek” olarak verilen bunun Tamam olduğunu kabul ediyorum ve meydan okuma ve quintopia'nın yorumlarında belirtildi “Eğer nihai sonuç yerel olarak desteklenen tamsayı tiplerine sığabiliyorsa, sonuç doğru olmalı. ne olabileceği konusunda herhangi bir kısıtlama yoktur. "


alternatif olarak

Çıktı formatlama kararlarına bağlı olarak, 92 baytta aşağıdakiler

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

Hangi yukarıdaki ile aynıdır, sadece kullanır biçimlendirme açık çıkış ile .ToString('G17')istenen basamak sayısını elde etmek. Bunun için 55 @(28)çıktı olacak3824345300380220.5


Edit1 - kurtulmak alarak Kaydedilen 17 byte $dve sadece doğrudan hesaplanmasında kullanılan hesaplama kurtulmak $k_mbiz döngü ise o ileri çekimi ile $k
açık biçimlendirme ile alternatif sürümü eklendi - Edit2


3

APL (Dyalog Genişletilmiş) , 9 bayt

×/2!/+\⍛,

Çevrimiçi deneyin!

APL'imden gelen fikri kullanarak multinomları içeren başka bir soruna cevap verdim .

Sol argümanı k'lerin listesi ve sağ argümanı n'dir. Test davaları, Adam'ın sol ve sağ argümanlarının ters çevrildiği çözümünü kabul edip etmediğini kontrol eder .

Nasıl çalışır

×/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!x(k1+k2++km)!(k1+k2)!k3!km!

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

==(k1+k2k1)(k1+k2+k3k1+k2)(k1++kmk1++km-1)


2

Mathematica, 26 bayt

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

Örnek:

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

Out[1]= 1934550571913396675776550070308250

2

Python 3, 93 91

Dennis ve FryAmTheEggman'a teşekkürler .

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

ntam sayı olarak, kyinelenebilir olarak.

Ungolfed:

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
Dinamik boşluk uzatma biti için dört yerine tek bir boşluk kullanabilirsiniz
Conor O'Brien

Sekmeleri kullandım, bu yazıya yer değiştirdiler. Bayt sayısı iyi görünüyor. Kayan nokta sonucu ve olası taşma konusunda emin değilim.
Trang Oul,

2
1. Bu yanlış bir sonuç veriyor 95, [65, 4, 4]. Girişin k_m içermediğine dikkat edin . 2. Hiç kullanıyor görünmüyorsunuz from functools import*.
Dennis,

2
1. Golf kodunuz kullanmaz reduce. 2. import math;f=math.factorialbir bayt kaydeder. 3. Python 2 saniye kurtulmak sağlayacak /içinde //.
Dennis,

1
Tanımlanması fkendi başınıza bazı bayt kaydeder : f=lambda x:0**x or x*f(x-1).
FryAmTheEggman

2

APL (Dyalog Unicode) , 16 bayt SBCS

Tamamen iş arkadaşımın matematiksel becerisine dayanan Marshall .

Anonim infix işlevi. Alır k sağ argüman gibi n sol argümanı.

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

Çevrimiçi deneyin!

{} Anonim lambda; sol argüman ( n ) ve sağ argüman ( k )

0,⍵k  sıfıra almak

¯1↓ bundan son ürünü bırak

+\ kümülatif toplamı

⍺- onu n'den çıkar

⍵! ( k ) bu

×/ bunun ürünü


1

PARI / GP, 43 bayt

Oldukça basit; biçimlendirmenin yanı sıra, ungolfed versiyonu da aynı olabilir.

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

1

Matlab 48 bayt

Sen sete ihtiyaç formatiçin longyüksek hassasiyet almak için önceden. O zaman oldukça basit:

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

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

 1.934550571913395e+33

1

Pyth, 10 bayt

/F.!MaQ-FQ

Çevrimiçi deneyin: Gösteri

Açıklama:

/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 bayt

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

kullanım

Daha büyük değerler için, xgenişletilmiş hassas tamsayıları belirtmek için bir soneki kullanılır.

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

açıklama

[(%*/)&:!],(-+/)  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 bayt

Ƹ«!R.«÷

Çevrimiçi deneyin! Açıklama:

Æ           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. ya da 4. adımı gerçekleştirmenin daha iyi yollarını bulamıyorum.




0

Clojure, 70 bayt

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

nÖncelikle tüm argümanları tek bir liste halinde alarak adsız bir işlev oluşturur .

Sadece lanet olası faktoring işlevini tanımlayan 30 karakter "israf". Oh iyi.


0

Perl 6 ,  52  50 bayt

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

Dene

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

Test et (sonuç, 1 paydası olan bir Rasyoneldir)

Expanded:

->     # 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」
      )
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.