计算多项式系数


27

是时候让所有人都可以参加另一个轻松的挑战了!

多项式定理指出: 计算多项式的n次幂的公式

括号中的表达式是多项式系数,定义为:

多项式系数

允许项k i覆盖n的所有整数分区,将给出Pascal的m -simplex的第n级。您的任务是计算该系数。

任务

编写一个程序或函数,该程序或函数使用m个数字nk 1k 2,...,k m-1,并输出或返回相应的多项式系数。如果需要,您的程序可以选择将m作为附加参数。注意,k m不在输入中。

  • 这些数字可以按喜欢的任何格式输入,例如分组到列表中或以一元编码或其他方式输入,只要多项式系数的实际计算是由您的代码执行的,而不是由编码过程执行的。

  • 输出格式同样具有灵活性。

  • 所有代码应在不到一分钟的时间内运行nm,直到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吗?
·奥布莱恩

@CᴏɴᴏʀO'Bʀɪᴇɴ如果使用64位浮点数,则将根本无法表示输入[1000 {999 ones}],因为该指数远远超出了64位浮点数可以表示的范围。(128位浮点数可能就足够了,但是我假设您想使用JavaScript的本机数字类型?)
Martin Ender

@MartinBüttner是的,这是一个正确的假设。
科纳·奥布莱恩

2
@quintopia“该是所有人都可以参加的又一个简单挑战的时候了!”。除我以外的所有人!(因为我不知道什么Pascals单纯形和多项式是D :)大声笑。
Ashwin Gupta

@AshwinGupta不用担心。您只需要在第二张图像中计算表达式就可以了!👍
quintopia

Answers:


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.

这几乎是我想到的最简单的算法。
quintopia '16

9

CJam,11个字节

l~_:-+:m!:/

首先输入为单个列表n

[95 65 4 4]

这个手柄输入最多nm1000几乎瞬间。

在这里测试。

说明

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的疯狂简洁印象深刻。
phor

@phord好吧,CJam对Jelly(或Pyth)不适合。但是我很惊讶自己最终变得如此紧凑。我的第一个解决方案有21个字节,虽然它似乎不是最佳的,但我认为我几乎不能将其削减一半。
马丁·恩德

4

MATL,21 15字节

让我们充分利用log-gamma函数。通过使用阶乘的对数而不是阶乘本身,可以避免内部溢出。

1+ZgiO$Gs-h1+Zgs-ZeYo

这在语言/编译器的当前版本(9.2.2)中有效,它早于此挑战。

输入为:首先是数字,然后是数字向量。结果生成为a 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
@丹尼斯嘿!真是一个惊喜!!!我要如何感谢你?我有一个建议:如果您来马德里,我欠您一顿
丰盛的

我真的很感激 在线上很棒。我们将如何处理修订?我仍在不断更新语言,您知道吗
Luis Mendo

现在,我正在手动更新解释器。如果您进行更新,请在第十九个字节中ping我,我将尽快将其拉出。-我将在不久的将来去马德里,所以我会紧记您的报价。;)
丹尼斯

@丹尼斯太好了!这样我们可以亲自见面!
路易斯·门多

4

PowerShell,91 74字节

!我对PPCG的第100个答案!

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

ew。肯定不会赢得最短代码。但是,使用了一些带有范围的整洁技巧。对于不熟悉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每次迭代时都会生成范围,该范围会留在管道中。这些流水线对象与第二个表达式range 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。我假设在挑战中指定了“输出格式同样灵活”,然后quintopia的注释“如果最终结果可以适合本机支持的整数类型,那么结果必须是准确的。如果不能,那里不受输出限制。”


或者

根据输出格式决定,以下为92字节

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

这是与上述相同,只是使用明确的输出格式.ToString('G17')实现的数字的期望数量。为此55 @(28)将输出3824345300380220.5


Edit1-删除$d并直接计算就节省了17个字节,并在$k_m循环时通过串起来省去了计算$k
2-添加了具有显式格式的替代版本


3

APL(Dyalog扩展),9字节

×/2!/+\⍛,

在线尝试!

利用我的APL回答中的想法解决另一个涉及多项式的挑战

一个默认函数,其左参数为k的列表,右参数为n。测试用例通过翻转左右参数来检查是否与Adam的解决方案相符。

怎么运行的

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

Mathematica,26个字节

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

例:

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

Out[1]= 1934550571913396675776550070308250

2

Python 3,93 91

感谢DennisFryAmTheEggman

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

我使用了选项卡,它们在这篇文章中被替换了。字节数似乎还可以。我不确定浮动结果和可能的溢出。
董里(Trang Oul)

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


1

PARI / GP,43个字节

非常简单;除了格式化外,非高尔夫版本可能完全相同。

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

1

Matlab 48字节

您需要预先设置formatlong获得更高的精度。然后,这非常简单:

@(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的Rational)

展开:

->     # 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」
      )
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.