|
hbghlyj
Posted at 2025-4-7 06:32:07
$f∘f∘f∘f∘f=f$
Last edited by hbghlyj at 2025-4-7 07:16:40n元集上的函数$f$的个数
1,4,25,224,2601,36352,588337,10809360,222264145,5057068256
在OEIS中没有找到,是不是算错了 - import math
- def precompute_ways_chains(max_n):
- """
- Precompute the number of ways to attach 'rem = n - M' elements as chains (of length up to 4)
- into any of M cycle nodes.
- Each of the 'rem' elements can form a chain of length 1..4 ending in a cycle node. We count
- how many ways they can form those chains collectively.
-
- We'll store these counts in ways_chains_table[n][M].
- """
- # Precompute factorials for speed
- factorials = [1]*(max_n+1)
- for i in range(1, max_n+1):
- factorials[i] = factorials[i-1]*i
- def multinomial(total, counts):
- # multinomial coefficient = total! / (counts[0]! * counts[1]! * ... )
- num = factorials[total]
- for c in counts:
- num //= factorials[c]
- return num
- ways_chains_table = [[0]*(max_n+1) for _ in range(max_n+1)]
-
- for n in range(1, max_n+1):
- for M in range(n+1):
- rem = n - M
- if rem < 0:
- continue
- total_ways = 0
- # We partition rem into (s1, s2, s3, s4) where s1 + s2 + s3 + s4 = rem
- # s1 = number of elements that map directly to a cycle node
- # s2 = number of elements that map to one of those s1 elements
- # s3 = number that map to an element among s2...
- # s4 = number that map to an element among s3...
- # Each chain ends at a cycle node, so effectively the chain length is from 1 up to 4.
- for s1 in range(rem+1):
- for s2 in range(rem+1 - s1):
- for s3 in range(rem+1 - s1 - s2):
- s4 = rem - s1 - s2 - s3
- # The multinomial factor to choose which elements go to s1, s2, s3, s4
- multi = multinomial(rem, (s1, s2, s3, s4))
- # attachments factor = M^s1 * s1^s2 * s2^s3 * s3^s4
-
- # If s1=0 but s2>0, that implies references to 0 existing elements => invalid
- if s1 == 0 and s2 > 0:
- continue
- if s2 == 0 and s3 > 0:
- continue
- if s3 == 0 and s4 > 0:
- continue
-
- attach_factor = (M**s1) * (s1**s2) * (s2**s3) * (s3**s4)
- total_ways += multi * attach_factor
- ways_chains_table[n][M] = total_ways
-
- return ways_chains_table
- def count_functions_power5(n, ways_chains_table):
- """
- Count the number of functions f: {1..n} -> {1..n} such that
- f(f(f(f(f(x))))) = f(x) for all x.
- Valid cycle lengths under this condition are 1, 2, and 4 because f^5(x)=f(x)
- implies the cycle length divides (5-1)=4 or is 1 itself. Then every non-cycle
- element must chain within up to 4 steps into a cycle node.
- """
- total = 0
- # c1: count of 1-cycles, c2: count of 2-cycles, c4: count of 4-cycles
- for c4 in range(n // 4 + 1):
- for c2 in range((n - 4*c4) // 2 + 1):
- c1_max = n - 2*c2 - 4*c4
- for c1 in range(c1_max + 1):
- # M = total cycle elements
- M = c1 + 2*c2 + 4*c4
- # Choose M distinct elements out of n
- ways_choose_M = math.comb(n, M)
- # Among these M, choose c1 for 1-cycles
- ways_choose_c1 = math.comb(M, c1)
- # Remaining M-c1 = 2*c2 + 4*c4 for the 2- and 4-cycles
- # We first choose which 2*c2 among these (2*c2 + 4*c4) will form the 2-cycles
- ways_choose_2c2 = math.comb(2*c2 + 4*c4, 2*c2)
- # Count ways to form c2 disjoint 2-cycles from 2*c2 distinct elements:
- ways_2cycles = math.factorial(2*c2) // (2**c2 * math.factorial(c2))
- # Count ways to form c4 disjoint 4-cycles from 4*c4 distinct elements:
- ways_4cycles = math.factorial(4*c4) // (4**c4 * math.factorial(c4))
-
- # Ways to attach the remaining n-M elements in chains of length <=4
- ways_attach = ways_chains_table[n][M]
-
- total += (ways_choose_M *
- ways_choose_c1 *
- ways_choose_2c2 *
- ways_2cycles *
- ways_4cycles *
- ways_attach)
- return total
- ways_chains_table = precompute_ways_chains(10)
- for i in range(1, 11):
- print(f"n={i}, count={count_functions_power5(i, ways_chains_table)}")
Copy the Code |
|