Problem:
Score : 600 points

Problem Statement

There are 2N balls, N white and N black, arranged in a row. The integers from 1 through N are written on the white balls, one on each ball, and they are also written on the black balls, one on each ball.
The integer written on the i-th ball from the left (1 ≤ i ≤ 2N) is a_i, and the color of this ball is represented by a letter c_i.
c_i = W represents the ball is white; c_i = B represents the ball is black.

Takahashi the human wants to achieve the following objective:

For every pair of integers (i,j) such that 1 ≤ i < j ≤ N, the white ball with i written on it is to the left of the white ball with j written on it.

For every pair of integers (i,j) such that 1 ≤ i < j ≤ N, the black ball with i written on it is to the left of the black ball with j written on it.

In order to achieve this, he can perform the following operation:

Swap two adjacent balls.

Find the minimum number of operations required to achieve the objective.

Constraints

1 ≤ N ≤ 2000

1 ≤ a_i ≤ N

c_i = W or c_i = B.

If i ≠ j, (a_i,c_i) ≠ (a_j,c_j).

Input

Input is given from Standard Input in the following format:

N
c_1 a_1
c_2 a_2
:
c_{2N} a_{2N}

Output

Print the minimum number of operations required to achieve the objective.

Sample Input 1

3
B 1
W 2
B 3
W 1
W 3
B 2

Sample Output 1

4

The objective can be achieved in four operations, for example, as follows:

Swap the black 3 and white 1.

Swap the white 1 and white 2.

Swap the black 3 and white 3.

Swap the black 3 and black 2.

Sample Input 2

4
B 4
W 4
B 3
W 3
B 2
W 2
B 1
W 1

Sample Output 2

18

Sample Input 3

9
W 3
B 1
B 4
W 1
B 5
W 9
W 2
B 6
W 5
B 3
W 8
B 9
W 7
B 2
B 8
W 4
W 6
B 7

Sample Output 3

41

Solution in Kotlin (1.0.0) (judge verdict: Time Limit Exceeded)

import java.lang.Math.min
class SumBinaryIndexedTree(val size:Int, private val mArray:Array<Int>){
    companion object {
        operator fun invoke(size:Int):SumBinaryIndexedTree{
            return SumBinaryIndexedTree(size, Array(size){0})
        }
    }
    private fun up(index:Int):Int{
        return index + ((index + 1) and (index.inv()))
    }
    private fun left(index:Int):Int{
        return index - ((index + 1) and (index.inv()))
    }
    operator fun get(index:Int):Int{
        var idx = left(index)
        var res = mArray[index]
        while (idx >= 0){
            res += mArray[idx]
            idx = left(idx)
        }
        return res
    }
    fun plusAt(index:Int, diff:Int):Unit{
        var idx = index
        while (idx < mArray.size){
            mArray[idx] = diff + mArray[idx]
            idx = up(idx)
        }
    }
}
fun main(args:Array<String>):Unit {
    val n = readLine()!!.toInt()
    val blackCost = Array(n + 1){Array(n + 1){0}}
    val whiteCost = Array(n + 1){Array(n + 1){0}}
    val blackBit = SumBinaryIndexedTree(n + 1)
    val blackAlreadyAppeared = Array(n + 1){false}
    var blackCount = 0
    val whiteBit = SumBinaryIndexedTree(n + 1)
    val whiteAlreadyAppeared = Array(n + 1){false}
    var whiteCount = 0
    for (i in 0 until 2 * n){
        val (c, num) = readLine()!!.split(' ')
        val number = num.toInt()
        when(c){
            "W" -> {
                whiteBit.plusAt(number, 1)
                ++whiteCount
                whiteAlreadyAppeared[number] = true
                whiteCost[number][0] = number - whiteBit[number] + blackCount
                for (j in 1 .. n){
                    whiteCost[number][j] = whiteCost[number][j - 1] - if(blackAlreadyAppeared[j]) 1 else 0
                }
            }
            else -> {
                blackBit.plusAt(number, 1)
                ++blackCount
                blackAlreadyAppeared[number] = true
                blackCost[number][0] = number - blackBit[number] + whiteCount
                for (j in 1..n) {
                    blackCost[number][j] = blackCost[number][j - 1] - if(whiteAlreadyAppeared[j]) 1 else 0
                }
            }
        }
    }
    println(f(n, n, blackCost, whiteCost, Array(n + 1){Array(n + 1){-1}}))
}
fun f(b:Int, w:Int, blackCost:Array<Array<Int>>, whiteCost:Array<Array<Int>>, memo:Array<Array<Int>>):Int{
    if (b == 0 && w == 0) return 0
    if (b < 0 || w < 0) return Int.MAX_VALUE shr 2
    if (memo[b][w] < 0){
        memo[b][w] = min(f(b - 1, w, blackCost, whiteCost, memo) + blackCost[b][w], f(b, w - 1, blackCost, whiteCost, memo) + whiteCost[w][b])
    }
    return memo[b][w]
}