# minimum cost to process m tasks where switching costs | function to find out the farthest position where one of the currently ongoing tasks will rehappen . ; iterate form last to current position and find where the task will happen next . ; find out maximum of all these positions and it is the farthest position . ; function to find out minimum cost to process all the tasks ; freqarr [ i ] [ j ] denotes the frequency of type j task after position i like in array 1 , 2 , 1 , 3 , 2 , 1 frequency of type 1 task after position 0 is 2. so , for this array freqarr [ 0 ] [ 1 ] = 2. here , i can range in between 0 to m - 1 and j can range in between 0 to m ( though there is not any type 0 task ) . ; fill up the freqarr vector from last to first . after m - 1 th position frequency of all type of tasks will be 0. then at m - 2 th position only frequency of arr [ m - 1 ] type task will be increased by 1. again , in m - 3 th position only frequency of type arr [ m - 2 ] task will be increased by 1 and so on . ; isrunning [ i ] denotes whether type i task is currently running in one of the cores . at the beginning no tasks are running so all values are false . ; cost denotes total cost to assign tasks ; truecount denotes number of occupied cores ; iterate through each task and find the total cost . ; ele denotes type of task . ; case 1 : if same type of task is currently running cost for this is 0. ; case 2 : same type of task is not currently running . ; subcase 1 : if there is at least one free core then assign this task to that core at a cost of 1 unit . ; subcase 2 : no core is free ; set minimum frequency to a big number ; set index of minimum frequency task to 0. ; find the minimum frequency task type ( miniind ) and frequency ( mini ) . ; if minimum frequency is zero then just stop the task and start the present task in that core . cost for this is 1 unit . ; if minimum frequency is nonzero then find the farthest position where one of the ongoing task will rehappen . stop that task and start present task in that core . ; find out the farthest position using find function ; return total cost ; 
def find(arr, pos, m, isRunning):
    d = [0] * (m + 1)
    for i in range(m - 1, pos, -1):
        if isRunning[arr[i]]:
            d[arr[i]] = i
    maxipos = 0
    for ele in d:
        maxipos = max(ele, maxipos)
    return maxipos


def mincost(n, m, arr):
    freqarr = [[]for i in range(m)]
    newvec = [0] * (m + 1)
    freqarr[m - 1] = newvec[:]
    for i in range(m - 2, -1, -1):
        nv = freqarr[i + 1][:]
        nv[arr[i + 1]] += 1
        freqarr[i] = nv[:]
    isRunning = [False] * (m + 1)
    cost = 0
    truecount = 0
    for i in range(0, m):
        ele = arr[i]
        if isRunning[ele]:
            continue
        else:
            if truecount < n:
                cost += 1
                truecount += 1
                isRunning[ele] = True
            else:
                mini = 100000
                miniind = 0
                for j in range(1, m + 1):
                    if isRunning[j] and mini > freqarr[i][j]:
                        mini = freqarr[i][j]
                        miniind = j
                if mini == 0:
                    isRunning[miniind] = False
                    isRunning[ele] = True
                    cost += 1
                else:
                    farpos = find(arr, i, m, isRunning)
                    isRunning[arr[farpos]] = False
                    isRunning[ele] = True
                    cost += 1
    return cost


if __name__ == "__main__":
    n1, m1 = 3, 6
    arr1 = [1, 2, 1, 3, 4, 1]
    print(mincost(n1, m1, arr1))
    n2, m2 = 2, 6
    arr2 = [1, 2, 1, 3, 2, 1]
    print(mincost(n2, m2, arr2))
    n3, m3 = 3, 31
    arr3 = [7, 11, 17, 10, 7, 10, 2, 9, 2, 18, 8, 10, 20, 10, 3,
            20, 17, 17, 17, 1, 15, 10, 8, 3, 3, 18, 13, 2, 10, 10, 11]
    print(mincost(n3, m3, arr3))

# Expected output:
4
4
18