การนับกลุ่ม Abelian ในขนาดที่กำหนด


14

พื้นหลัง

ครั้งที่แล้วเรานับกลุ่มของขนาดที่กำหนดซึ่งเป็นปัญหาที่ไม่สำคัญ

เวลานี้เราจะนับเฉพาะกลุ่มชาว Abelianเช่นกลุ่มที่มีการดำเนินการสับเปลี่ยน อย่างเป็นทางการเป็นกลุ่ม(G, *)เป็นคริสต์ถ้าx * y ที่ y = x *สำหรับทุกx, yในG

ปัญหานี้ง่ายขึ้นมากดังนั้นเราจะนับพวกมันอย่างมีประสิทธิภาพ

งาน

เขียนโปรแกรมหรือฟังก์ชั่นที่ยอมรับจำนวนเต็มไม่เป็นลบnเป็น input และพิมพ์หรือส่งกลับจำนวนของกลุ่มคริสต์ไม่ใช่ isomorphic ของการสั่งซื้อn

วิธีหนึ่งในการคำนวณจำนวนกลุ่ม - ซึ่งเราจะแสดงโดยA (n) - คือการสังเกตสิ่งต่อไปนี้:

  • A (0) = 0

  • ถ้าหน้าเป็นนายก(หน้าk )จะเท่ากับจำนวนของพาร์ทิชันจำนวนเต็มของk (cfr. OEIS A000041 )

  • ถ้าn = mkและและkจะร่วมนายกA (n) = A (เมตร) 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 และขนาดการลงทะเบียนที่สามารถเก็บอินพุตได้รหัสของคุณควรใช้งานได้ (ตามทฤษฎี) สำหรับจำนวนเต็มขนาดใหญ่โดยพลการ

  • รหัสของคุณจะต้องทำงานกับจำนวนเต็มทั้งหมดระหว่าง0ถึง2 63 - 1และเสร็จสิ้นภายใน 10 นาทีบนเครื่องของฉัน (Intel i7-3770, 16 GiB RAM, Fedora 21)

    โปรดตรวจสอบให้แน่ใจว่าคุณได้กำหนดรหัสสำหรับกรณีทดสอบสามครั้งล่าสุดก่อนส่งคำตอบ

  • บิวด์อินที่FiniteAbelianGroupCountไม่ได้รับอนุญาตให้ทำภารกิจนี้เช่น Mathematica

  • บิวด์อินที่ไม่อนุญาตให้ส่งคืนหรือนับพาร์ติชันจำนวนเต็มของตัวเลขหรือพาร์ติชันของรายการ

  • ใช้กฎมาตรฐานของ


ระบบการแยกตัวประกอบเฉพาะของ Pyth นั้นช้าเกินไปสำหรับความท้าทายนี้ - ฉันจำเป็นต้องแก้ไข
isaacg

คำตอบ:


3

CJam ( 39 38 ไบต์)

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

การสาธิตออนไลน์

สิ่งนี้เป็นไปตามบรรทัดที่แนะนำในการค้นหาการแยกตัวประกอบสำคัญ ( mF) และคำนวณพาร์ติชันของแต่ละพาวเวอร์

มีสองกรณีพิเศษสำหรับmF: มัน0เป็นปัจจัย0^1และเป็น1 1^1หลังไม่จำเป็นต้องได้รับการดูแลเป็นพิเศษ: มีกลุ่ม Abelian หนึ่งกลุ่มที่มีขนาด 1 และอีกหนึ่งพาร์ติชันที่ 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 bytes

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

ใช้mFตัวประกอบแบบบิวด์อินของ CJam และพอร์ตที่บันทึกความจำของฟังก์ชันหมายเลขพาร์ติชัน Python นี้:

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

หรือ ungolfed:

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*

ลองออนไลน์

ตัวอย่างการทดสอบครั้งสุดท้ายใช้เวลาตลอดไป (หรืออย่างน้อยก็นานเกินกว่าที่ฉันจะรอ) ในล่ามออนไลน์ แต่จบใน 17 วินาทีด้วย CJam รุ่นออฟไลน์บนแล็ปท็อปของฉัน ตัวอย่างการทดสอบอื่น ๆ ทั้งหมดนั้นค่อนข้างรวดเร็ว

สิ่งนี้ใช้ CJam mFดำเนินการซึ่งให้การแยกตัวประกอบเฉพาะด้วยเลขชี้กำลัง ผลที่ได้คือผลิตภัณฑ์ของพาร์ติชันนับสำหรับแต่ละเลขชี้กำลัง

ส่วนหลักของรหัสกำลังคำนวณจำนวนพาร์ติชัน ฉันใช้อัลกอริทึมแบบเรียกซ้ำบนหน้าวิกิพีเดียโดยใช้ตัว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.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.