import math
def rank_permutation(seq):
ref = sorted(seq)
if ref == seq:
return 0
else:
rank = 0
f = math.factorial(len(seq)-1)
for x in ref:
if x < seq[0]:
rank += f
else:
rank += rank_permutation(seq[1:]) if seq[1:] else 0
return rank
def unrank_permutation(n, k):
"""
Generates the k-th permutation of size n.
Args:
n: The size of the permutation.
k: The rank of the permutation (0-indexed).
Returns:
A list representing the k-th permutation of size n.
"""
if not (0 <= k < math.factorial(n)):
raise ValueError("Rank k is out of bounds.")
items = list(range(n))
permutation = []
temp_k = k
for i in range(n, 0, -1):
index = temp_k // math.factorial(i - 1)
temp_k %= math.factorial(i - 1)
permutation.append(items.pop(index))
return permutation
def binomial(n,k):
if n < 0 or k < 0 or k > n: return 0
b = 1
for i in range(k): b = b*(n-i)//(i+1)
return b
def unchoose(n,S):
k = len(S)
if k == 0 or k == n: return 0
j = S[0]
if k == 1: return j
S = [x-1 for x in S]
if not j: return unchoose(n-1,S[1:])
return binomial(n-1,k-1)+unchoose(n-1,S)
def choose(X,k):
n = len(X)
if k < 0 or k > n: return []
if not k: return [[]]
if k == n: return [X]
return [X[:1] + S for S in choose(X[1:],k-1)] + choose(X[1:],k)
def unget(perm, n):
zipped = zip(perm, range(len(perm)))
return list(zipped)
print(unget([0, 2, 1], 4))
aW1wb3J0IG1hdGgKCgpkZWYgcmFua19wZXJtdXRhdGlvbihzZXEpOgogICAgcmVmID0gc29ydGVkKHNlcSkKICAgIGlmIHJlZiA9PSBzZXE6CiAgICAgICAgcmV0dXJuIDAKICAgIGVsc2U6CiAgICAgICAgcmFuayA9IDAKICAgICAgICBmID0gbWF0aC5mYWN0b3JpYWwobGVuKHNlcSktMSkKICAgICAgICBmb3IgeCBpbiByZWY6CiAgICAgICAgICAgIGlmIHggPCBzZXFbMF06CiAgICAgICAgICAgICAgICByYW5rICs9IGYKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIHJhbmsgKz0gcmFua19wZXJtdXRhdGlvbihzZXFbMTpdKSBpZiBzZXFbMTpdIGVsc2UgMAogICAgICAgICAgICAgICAgcmV0dXJuIHJhbmsKCgpkZWYgdW5yYW5rX3Blcm11dGF0aW9uKG4sIGspOgogICAgIiIiCiAgICBHZW5lcmF0ZXMgdGhlIGstdGggcGVybXV0YXRpb24gb2Ygc2l6ZSBuLgoKICAgIEFyZ3M6CiAgICAgICAgbjogVGhlIHNpemUgb2YgdGhlIHBlcm11dGF0aW9uLgogICAgICAgIGs6IFRoZSByYW5rIG9mIHRoZSBwZXJtdXRhdGlvbiAoMC1pbmRleGVkKS4KCiAgICBSZXR1cm5zOgogICAgICAgIEEgbGlzdCByZXByZXNlbnRpbmcgdGhlIGstdGggcGVybXV0YXRpb24gb2Ygc2l6ZSBuLgogICAgIiIiCiAgICBpZiBub3QgKDAgPD0gayA8IG1hdGguZmFjdG9yaWFsKG4pKToKICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCJSYW5rIGsgaXMgb3V0IG9mIGJvdW5kcy4iKQoKICAgIGl0ZW1zID0gbGlzdChyYW5nZShuKSkKICAgIHBlcm11dGF0aW9uID0gW10KICAgIHRlbXBfayA9IGsKCiAgICBmb3IgaSBpbiByYW5nZShuLCAwLCAtMSk6CiAgICAgICAgaW5kZXggPSB0ZW1wX2sgLy8gbWF0aC5mYWN0b3JpYWwoaSAtIDEpCiAgICAgICAgdGVtcF9rICU9IG1hdGguZmFjdG9yaWFsKGkgLSAxKQogICAgICAgIHBlcm11dGF0aW9uLmFwcGVuZChpdGVtcy5wb3AoaW5kZXgpKQogICAgCiAgICByZXR1cm4gcGVybXV0YXRpb24KCgpkZWYgYmlub21pYWwobixrKToKICAgIGlmIG4gPCAwIG9yIGsgPCAwIG9yIGsgPiBuOiByZXR1cm4gMAogICAgYiA9IDEKICAgIGZvciBpIGluIHJhbmdlKGspOiBiID0gYioobi1pKS8vKGkrMSkKICAgIHJldHVybiBiCgoKZGVmIHVuY2hvb3NlKG4sUyk6CiAgICBrID0gbGVuKFMpCiAgICBpZiBrID09IDAgb3IgayA9PSBuOiByZXR1cm4gMAogICAgaiA9IFNbMF0KICAgIGlmIGsgPT0gMTogcmV0dXJuIGoKICAgIFMgPSBbeC0xIGZvciB4IGluIFNdCiAgICBpZiBub3QgajogcmV0dXJuIHVuY2hvb3NlKG4tMSxTWzE6XSkKICAgIHJldHVybiBiaW5vbWlhbChuLTEsay0xKSt1bmNob29zZShuLTEsUykKCgpkZWYgY2hvb3NlKFgsayk6CiAgICBuID0gbGVuKFgpCiAgICBpZiBrIDwgMCBvciBrID4gbjogcmV0dXJuIFtdCiAgICBpZiBub3QgazogcmV0dXJuIFtbXV0KICAgIGlmIGsgPT0gbjogcmV0dXJuIFtYXQogICAgcmV0dXJuIFtYWzoxXSArIFMgZm9yIFMgaW4gY2hvb3NlKFhbMTpdLGstMSldICsgY2hvb3NlKFhbMTpdLGspCgoKZGVmIHVuZ2V0KHBlcm0sIG4pOgogIHppcHBlZCA9IHppcChwZXJtLCByYW5nZShsZW4ocGVybSkpKQogIHJldHVybiBsaXN0KHppcHBlZCkKCnByaW50KHVuZ2V0KFswLCAyLCAxXSwgNCkpCg==