def nextperm( perm ):
    n = len(perm)

    # start at the last position
    j = n-1

    #find last ascending pair
    while True:
        if j == 0:
            return False # no next permutation
        if perm[j-1] > perm[j]:
            j -= 1
        else: break

    j1 = j-1 # remember  position

    # find smallest bigger element than perm[j1]
    # to the right of j1
    while j < n and perm[j] > perm[j1]:
        j += 1
    # index of that element:
    j -= 1

    # swap perm[j] and perm[j1]
    perm[j], perm[j1] = perm[j1], perm[j]

    # reverse sequence to the right of j1
    j1 += 1; j = n-1
    while j1 < j:
        perm[j], perm[j1] = perm[j1], perm[j]
        j1 += 1; j -= 1

    return True


def factorial( n ):
    f = 1
    while n > 1:
        f *= n
        n -= 1
    return f


def rankPermutation( perm ):
    n = len( perm )
    if n == 1: return 0

    rank = (perm[0]-1) * factorial(n-1)

    # consider the permutation without the 1st element
    perm1 = perm[1:]  # copy w/o perm[0]
    # "normalize" the resulting permutation
    # for recursive processing
    for j in range(len(perm1)):
        if perm1[j] > perm[0]:
            perm1[j] -= 1

    return rank + rankPermutation( perm1 )


def unrankPerm( rank, permLen ):
    n = permLen # just synonym
    if n == 1: return [1]  # simplest possible permutation

    # count how many blocks of size n-1
    # would fit into list of all permutations
    # before the given rank
    blocksCount = rank // factorial(n-1)  # integer div

    # construct the first element of the permutation
    firstElem = blocksCount + 1

    # calculate remaining rank to feed into recursion
    rank = rank % factorial(n-1)

    # exploit recursion
    perm = unrankPerm( rank, n-1)

    # "fit" the returned permutation to current size n
    for j in range( len(perm)):
        if perm[j] >= firstElem:
            perm[j] += 1

    return [firstElem] + perm # concatenate lists



def pr( x, a ):
    n = ("   "+str(x))[-3:]
    print( n +" ("+  " ".join(list(map(str, a))) + ")"  )

def isDerangement( p ):
    for i in range(len(p)):
        if i == p[i]: return False
    return True


# --------------------------------------------------------------------------------
#                 M A I N
#  --------------------------------------------------------------------------------

p = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
p = [0,1,2,3,4,5,6,7,8,9,10]
p = [1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14,17,16,19,18]
rank = 0
ord = 1
while True:
    #pr(rank, p)
    #w = rankPermutation( p )
    if isDera( p ):
        if ord % 1000 == 0:
            print(ord, p)
        if ord == 1000000: break
        ord += 1
    rank += 1
    if not nextperm( p ):
        break

exit()







#for w in range(120):
#    print( unrankPerm(w, 5) )

z = unrankPerm(1000, 7)
pr( 0, z )

p = [2, 4, 6, 8, 10, 9, 7, 5, 3, 1]
w = rankPermutation( p )
print(w)

exit()

p = [1,2,3,4,5]
rank = 0
while True:
    pr(rank, p)
    w = rankPermutation( p )
    print(w)
    rank += 1
    if not nextperm( p ):
        break

exit()


