翻译版原题如下,取自:https://pe-cn.github.io/902/

第一版
python
def factorial(n):
"""计算n的阶乘"""
result = 1
for i in range(2, n + 1):
result *= i
return result
def rank(perm):
"""
计算置换perm的rank(字典序位置,从1开始)
perm是一个列表,perm[i]表示位置i+1的值
"""
n = len(perm)
r = 1 # rank从1开始
for i in range(n):
# 计算在位置i,有多少个未使用的数小于perm[i]
count = 0
for j in range(i + 1, n):
if perm[j] < perm[i]:
count += 1
r += count * factorial(n - i - 1)
return r
def compute_sigma(m):
"""
计算σ置换
n = m(m+1)/2
σ(i) = k(k-1)/2 + 1 如果存在k使得i = k(k+1)/2
σ(i) = i + 1 其他情况
"""
n = m * (m + 1) // 2
sigma = [0] * (n + 1) # 1-indexed
# 标记特殊位置
special_positions = set()
for k in range(1, m + 1):
pos = k * (k + 1) // 2
special_positions.add(pos)
for i in range(1, n + 1):
if i in special_positions:
# 找到k使得i = k(k+1)/2
for k in range(1, m + 1):
if i == k * (k + 1) // 2:
sigma[i] = k * (k - 1) // 2 + 1
break
else:
sigma[i] = i + 1
return sigma[1:] # 返回0-indexed列表
def compute_tau(n):
"""
计算τ置换
τ(i) = ((10^9 + 7) * i mod n) + 1
"""
MOD_BASE = 10**9 + 7
tau = [0] * (n + 1) # 1-indexed
for i in range(1, n + 1):
tau[i] = ((MOD_BASE * i) % n) + 1
return tau[1:] # 返回0-indexed列表
def compute_inverse(perm):
"""计算置换perm的逆置换"""
n = len(perm)
inv = [0] * n
for i in range(n):
inv[perm[i] - 1] = i + 1 # perm是1-indexed的值
return inv
def compute_pi(m):
"""
计算π置换
π(i) = τ^(-1)(σ(τ(i)))
"""
n = m * (m + 1) // 2
sigma = compute_sigma(m)
tau = compute_tau(n)
tau_inv = compute_inverse(tau)
# π(i) = τ^(-1)(σ(τ(i)))
# 注意:sigma, tau, tau_inv都是0-indexed列表,但存储的是1-indexed的值
pi = [0] * n
for i in range(n):
# i是0-indexed的位置,对应1-indexed的i+1
tau_i = tau[i] # τ(i+1),这是1-indexed的值
sigma_tau_i = sigma[tau_i - 1] # σ(τ(i+1))
pi[i] = tau_inv[sigma_tau_i - 1] # τ^(-1)(σ(τ(i+1)))
return pi
def compose_permutations(p1, p2):
"""
计算置换的复合 p1 ∘ p2
即先应用p2,再应用p1
"""
n = len(p1)
result = [0] * n
for i in range(n):
# p2[i]是位置i+1映射到的值(1-indexed)
# 需要在p1中找到这个值对应的位置
result[i] = p1[p2[i] - 1]
return result
def power_permutation(perm, k):
"""计算置换perm的k次幂"""
n = len(perm)
if k == 0:
return list(range(1, n + 1)) # 恒等置换
result = list(range(1, n + 1)) # 恒等置换
base = perm[:]
while k > 0:
if k % 2 == 1:
result = compose_permutations(base, result)
base = compose_permutations(base, base)
k //= 2
return result
def compute_P(m):
"""
计算P(m) = Σ(k=1 to m!) rank(π^k)
"""
n = m * (m + 1) // 2
pi = compute_pi(m)
total = 0
m_fact = factorial(m)
# 计算π的幂
pi_power = list(range(1, n + 1)) # 初始为恒等置换
for k in range(1, m_fact + 1):
pi_power = compose_permutations(pi, pi_power)
r = rank(pi_power)
total += r
if k <= 3 or k == m_fact: # 只显示前几个和最后一个
print(f" k={k}: rank={r}")
return total
# 验证例子
"""
print("验证例子:")
print("rank([2,1,3]) =", rank([2, 1, 3]))
print("期望值:3")
print()
print("计算P(2):")
p2 = compute_P(2)
print(f"P(2) = {p2}")
print(f"期望值:4")
print(f"匹配:{p2 == 4}")
print()
print("计算P(3):")
p3 = compute_P(3)
print(f"P(3) = {p3}")
print(f"期望值:780")
print(f"匹配:{p3 == 780}")
print()
print("计算P(4):")
p4 = compute_P(4)
print(f"P(4) = {p4}")
print(f"期望值:38810300")
print(f"匹配:{p4 == 38810300}")
"""
print("计算P(10):")
p10 = compute_P(10)
print(f"P(10) = {p10}")
优化版
python
import math
from math import gcd
MOD = 10**9 + 7
def factorial_mod(n, mod):
"""计算n! mod mod"""
result = 1
for i in range(2, n + 1):
result = (result * i) % mod
return result
def factorial(n):
"""计算n的阶乘(完整值)"""
result = 1
for i in range(2, n + 1):
result *= i
return result
def rank_mod(perm, mod):
"""
计算置换perm的rank(字典序位置,从1开始),并对mod取模
使用优化的算法,边计算边取模
"""
n = len(perm)
r = 1 # rank从1开始
# 预计算阶乘
facts = [1] * (n + 1)
for i in range(1, n + 1):
facts[i] = (facts[i-1] * i) % mod
for i in range(n):
# 计算在位置i,有多少个未使用的数小于perm[i]
count = 0
for j in range(i + 1, n):
if perm[j] < perm[i]:
count += 1
r = (r + count * facts[n - i - 1]) % mod
return r
def compute_sigma(m):
"""
计算σ置换
n = m(m+1)/2
σ(i) = k(k-1)/2 + 1 如果存在k使得i = k(k+1)/2
σ(i) = i + 1 其他情况
"""
n = m * (m + 1) // 2
sigma = [0] * (n + 1) # 1-indexed
# 标记特殊位置
special_positions = set()
for k in range(1, m + 1):
pos = k * (k + 1) // 2
special_positions.add(pos)
for i in range(1, n + 1):
if i in special_positions:
# 找到k使得i = k(k+1)/2
for k in range(1, m + 1):
if i == k * (k + 1) // 2:
sigma[i] = k * (k - 1) // 2 + 1
break
else:
sigma[i] = i + 1
return sigma[1:] # 返回0-indexed列表
def compute_tau(n):
"""
计算τ置换
τ(i) = ((10^9 + 7) * i mod n) + 1
"""
MOD_BASE = 10**9 + 7
tau = [0] * (n + 1) # 1-indexed
for i in range(1, n + 1):
tau[i] = ((MOD_BASE * i) % n) + 1
return tau[1:] # 返回0-indexed列表
def compute_inverse(perm):
"""计算置换perm的逆置换"""
n = len(perm)
inv = [0] * n
for i in range(n):
inv[perm[i] - 1] = i + 1 # perm是1-indexed的值
return inv
def compute_pi(m):
"""
计算π置换
π(i) = τ^(-1)(σ(τ(i)))
"""
n = m * (m + 1) // 2
sigma = compute_sigma(m)
tau = compute_tau(n)
tau_inv = compute_inverse(tau)
# π(i) = τ^(-1)(σ(τ(i)))
pi = [0] * n
for i in range(n):
tau_i = tau[i] # τ(i+1),这是1-indexed的值
sigma_tau_i = sigma[tau_i - 1] # σ(τ(i+1))
pi[i] = tau_inv[sigma_tau_i - 1] # τ^(-1)(σ(τ(i+1)))
return pi
def compose_permutations(p1, p2):
"""
计算置换的复合 p1 ∘ p2
即先应用p2,再应用p1
"""
n = len(p1)
result = [0] * n
for i in range(n):
result[i] = p1[p2[i] - 1]
return result
def get_cycle_lengths(perm):
"""
获取置换的循环分解中各个循环的长度
"""
n = len(perm)
visited = [False] * n
cycle_lengths = []
for i in range(n):
if not visited[i]:
length = 0
j = i
while not visited[j]:
visited[j] = True
j = perm[j] - 1 # perm[j]是1-indexed的值
length += 1
cycle_lengths.append(length)
return cycle_lengths
def compute_permutation_order(perm):
"""
计算置换的阶(order)
阶是所有循环长度的最小公倍数
"""
cycle_lengths = get_cycle_lengths(perm)
order = 1
for length in cycle_lengths:
order = lcm(order, length)
return order
def lcm(a, b):
"""计算最小公倍数"""
return a * b // gcd(a, b)
def compute_P_optimized(m):
"""
计算P(m) = Σ(k=1 to m!) rank(π^k) mod (10^9 + 7)
利用置换的周期性进行优化
"""
n = m * (m + 1) // 2
pi = compute_pi(m)
# 计算π的阶
order = compute_permutation_order(pi)
print(f"置换π的阶: {order}")
# 计算m!
m_fact = factorial(m)
print(f"m! = {m_fact}")
# 计算一个周期内的rank和
print(f"计算一个周期内的rank和(需要计算{order}次)...")
cycle_sum = 0
pi_power = list(range(1, n + 1)) # 初始为恒等置换
# 只计算前几个用于验证
for k in range(1, min(order, 4) + 1):
pi_power = compose_permutations(pi, pi_power)
r = rank_mod(pi_power, MOD)
cycle_sum = (cycle_sum + r) % MOD
print(f" k={k}: rank mod (10^9+7) = {r}")
# 如果order很小,计算完整的周期和
if order <= 10000:
for k in range(4, order):
pi_power = compose_permutations(pi, pi_power)
r = rank_mod(pi_power, MOD)
cycle_sum = (cycle_sum + r) % MOD
else:
# 如果order很大,需要继续计算(这里可能需要更长时间的计算)
print(f" 警告:阶{order}很大,继续计算可能需要较长时间...")
for k in range(4, order):
pi_power = compose_permutations(pi, pi_power)
r = rank_mod(pi_power, MOD)
cycle_sum = (cycle_sum + r) % MOD
if k % 100000 == 0:
print(f" 已计算到k={k}")
print(f"一个周期内的rank和: {cycle_sum}")
# 计算P(m)
# P(m) = (m!/order) * cycle_sum + 剩余部分
quotient = m_fact // order
remainder = m_fact % order
print(f"m! / order = {quotient}, 余数 = {remainder}")
# 计算剩余部分
remaining_sum = 0
if remainder > 0:
print(f"计算剩余{remainder}项...")
pi_power = list(range(1, n + 1))
for k in range(1, remainder + 1):
pi_power = compose_permutations(pi, pi_power)
r = rank_mod(pi_power, MOD)
remaining_sum = (remaining_sum + r) % MOD
# P(m) = quotient * cycle_sum + remaining_sum
result = (quotient % MOD * cycle_sum % MOD + remaining_sum) % MOD
return result
# 验证例子
"""
print("=" * 60)
print("验证例子:")
print("rank([2,1,3]) =", rank_mod([2, 1, 3], MOD))
print("期望值:3")
print()
print("=" * 60)
print("计算P(2):")
p2 = compute_P_optimized(2)
print(f"P(2) = {p2}")
print(f"期望值:4")
print(f"匹配:{p2 == 4}")
print()
print("=" * 60)
print("计算P(3):")
p3 = compute_P_optimized(3)
print(f"P(3) = {p3}")
print(f"期望值:780")
print(f"匹配:{p3 == 780}")
print()
print("=" * 60)
print("计算P(4):")
p4 = compute_P_optimized(4)
print(f"P(4) = {p4}")
print(f"期望值:38810300")
print(f"匹配:{p4 == 38810300}")
"""
print("计算P(10):")
p10 = compute_P_optimized(10)
print(f"P(14) = {p10}")
里题目要求的p(100)还很远,但理解力和正确性、简单的优化能力都不错了。