计算给定大小的阿贝尔群


14

背景

上一次,我们计算了给定大小的组,这不是一个简单的问题。

这次,我们将仅计算Abelian组,即具有可交换运算的组。形式上,一组(G,*)是阿贝尔如果X * Y = Y * X为所有的x,yģ

这种方法使问题变得更加简单,因此我们将有效地对其进行计数。

任务

编写一个程序或函数,该程序或函数接受一个非负整数n作为输入,并打印或返回n阶的非同构阿贝尔群。

一种计算组数的方法(将用A(n)表示是通过观察以下内容:

  • A(0)= 0

  • 如果p是素数,则A(p k等于k的整数分区。(由OEIS A000041提供

  • 如果n = mk,并且mk是互质的,则A(n)= A(m)A(k)

您可以使用此方法或任何其他方法来计算A(n)

测试用例

Input               Output
0                   0
1                   1
2                   1
3                   1
4                   2
5                   1
6                   1
7                   1
8                   3
9                   2
10                  1
11                  1
12                  2
13                  1
14                  1
15                  1
16                  5
17                  1
18                  2
19                  1
20                  2
4611686018427387904 1300156
5587736968198167552 155232
9223371994482243049 2

(摘自OEIS A000688

附加规则

  • 给定足够的时间,RAM和可以容纳输入的寄存器大小,理论上,您的代码应适用于任意大的整数。

  • 您的代码必须为之间的所有整数的工作02 63 1 -中和完成在我的机器上10分钟(英特尔i7-3770,16吉布RAM,Fedora的21)。

    在提交答案之前,请确保您为最后三个测试用例安排了时间。

  • FiniteAbelianGroupCount不允许使用琐碎该任务的内置程序,例如Mathematica 。

  • 不允许内置函数返回或计算数字的整数分区或列表的分区。

  • 适用标准规则。


Pyth的素数分解系统对于此挑战来说太慢了-我需要解决这个问题。
isaacg

Answers:


3

CJam(39 38字节)

qimF{~M\{_ee{~\)<1b}%1+a\+}*0=1be&}%:*

在线演示

这遵循以下建议行:找到素数分解(mF),然后计算每个幂的分区并取其乘积。

有两种特殊情况mF:它0作为as 0^11as 1^1。后者不需要特殊处理:有一个大小为1的Abelian组和一个分区为1的分区。但是,零确实需要特殊情况。

分区计数使用的递归对A008284(n, k)进行划分,将分区划分为n多个k部分。在OEIS中,它表示为

T(n, k) = Sum_{i=1..k} T(n-k, i), for 1<=k<=n-1; T(n, n) = 1 for n >= 1.

但我认为这是更有益思考的总和不等1min(k, n-k)

解剖

q~              e# Parse input into an integer
mF              e# Factorise it
{               e# For each factor p^a
  ~             e#   Split the array [p a]
                e#   The following lines count partitions of a
                e#   (Note: they would be buggy if a were ever 0, but it isn't)
  M\{           e#   Starting with a table of zero rows, repeat a times
    _ee         e#     Copy table and pair each row with its index
    {~\)<1b}%   e#     Extract that prepended index and use it to sum for each j
                e#     the first jth items of row j
    1+          e#     Append a 1 for P(i, i)
    a\+         e#     Prepend the new row to the table (which is stored in reverse)
  }*
  0=1b          e#   Sum the elements in the latest (first) row

  e&            e#   If p was 0 then replace with 0
}%
:*              e# Take the product

5

CJam,50 49 47 43字节

ri_mF{1=_L{1$0>{,f{):X-Xj}:+}{;!}?}2j}%:*e&

使用CJam的内置mF分解和该Python分区号函数的备注端口:

p=lambda n,x:n==0 or n>0and sum(p(n+~a,a+1)for a in range(x))

或未打高尔夫球:

def p(n, x): # Call like p(n, n). n is number remaining, x is max part size
  if n > 0:
    return sum(p(n-a-1,a+1)for a in range(x))
  else:
    return (n==0)

就像@RetoKoradi的答案一样,最后一种情况在脱机解释器上花费大约17秒,因为那是CJam分解该数字所花费的时间。因此,我将其排除在此在线测试套件之外

完整说明

[Main body]
ri                                Read input and convert to int
  _          e&                   Logical AND input with final result to special case 0 
   mF                             Factorise input into [base, exponent] pairs
     {...}%                       Map, converting each pair to a partition number
           :*                     Take product

[Pair -> partition]
1=_                               Get exponent and copy (n,x in above Python)
   L                              Initialise empty cache
    {                       }2j   Memoise with 2 arguments
     1$0>                         Check if n > 0
         {            }{  }?      Execute first block if yes, else second block
                        ;!        Return (n == 0)
          ,f{      }              For each a in range(x) ...
             ):X-Xj               Call p(n-a-1,a+1) recursively
                    :+            Sum the results

4

Mathematica,96 94 88字节

f=1##&@@#&;f[SeriesCoefficient[1/f[1-x^Range@#],{x,0,#}]&/@Last/@FactorInteger@#]Sign@#&

我对Mathematica并不那么熟练,但是我想尝试一下。感谢@MartinBüttner提供-6个字节。

这将生成函数公式用于整数分区。


3

CJam,58个字节

li_mF{1=_L{_1>{_2$<{\;_j}{\,f{)_@\-j}:+}?}{;;1}?}2j}%:*\g*

在线尝试

最后一个测试示例在在线解释器中花费了永久时间(或者至少比我愿意等待的时间更长),但是在笔记本电脑上使用离线版本的CJam可以在17秒内完成。所有其他测试示例几乎都是瞬时的。

这使用CJam mF运算符,该运算符提供了带指数的质因子分解。然后,结果是每个指数的分区计数的乘积。

该代码的主要部分是计算分区计数。我在Wikipedia页面上实现了递归算法,使用j支持带有便笺的递归的运算符。

说明:

li    Get input and convert to int.
_     Make a copy to handle 0 special case at the end.
mF    Factorization with exponents.
{     Loop over factors.
  1=    Take exponent from [factor exponent] pair.
  _     Repeat it, recursive calls are initiated with p(n, n).
  L     Empty list as start point of memoization state.
  {     Start recursive block. Argument order is (m, n), opposite of Wikipedia.
    _1>   Check for n > 1.
    {     Start n > 1 case.
      _2$   Copy both m and n.
      <     Check for n < m.
      {     n < m case.
        \;    Pop m.
        _     Copy n.
        j     Make the p(n, n) recursive call.
      }     End n < m case.
      {     Main part of algorithm that makes recursive calls in loop.
        \,    Generate [0 1 ... m-1] range for k.
        f{    Start loop over k.
          )     Increment, since k goes from 1 to m.
          _     Copy k.
          @\    Rotate n to top, and swap. Now have k n k at top of stack.
          -     Subtract, now have k n-k at top of stack.
          j     Make the p(n-k, k) recursive call.
        }     End loop over k.
        :+    Sum up all the values.
      }?    Ternaray operator for n < m condition.
    }     End n > 1 case.
    {     n <= 1 case.
      ;;1   Pop m, n values, and produce 1 as result.
    }?    Ternary operator for n > 1 condition.
  }2j   Recursive call with memoization, using 2 values.
}%    End loop over factors.
:*    Multiply all values.
\     Swap original input to top.
g     Signum.
*     Multiply to get 0 output for 0 input.
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.