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 C++14 (GCC 5.4.1) (judge verdict: Runtime Error)

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

#define REP(i,n) for(int i=0;i<n;++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 1
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const int MOD = 1000000007;
#define MAX_N 2010
#define MAX_2N 4010

ll N;
char C[MAX_N] = {};
ll A[MAX_N] = {};

// 1-indexed であることに注意
template<typename T>
class BITree {
    public:
        BITree(int n) : m_N(n + 1) { m_Tree.assign(m_N, 0); }
        // [1, i] の合計値を返す (log m_N)
        // 閉区間であることに注意
        T Sum(int i) {
            if(i < 1 || i >= m_N) { return 0; }
            T s = 0;
            while(i > 0) { s += m_Tree[i]; i -= i & -i; }
            return s;
        }
        // [i, j] の合計値を返す (log m_N)
        // i < j
        // 閉区間であることに注意
        T Sum(int i, int j) {
            if(i > j) { return 0; }
            return Sum(j) - Sum(i-1);
        }
        // i 番目の要素(1-indexed)に x を足して更新 O(log m_N)
        void Add(int i, T x){ while(i < m_N) { m_Tree[i] += x; i += i & -i; } }
    private:
        int m_N;            // 要素数
        vector<T> m_Tree;   // BIT 本体
};

// 順列 p の転倒数を返す (転倒数：順番を維持したままペアをとったとき、左の数字の方が大きいペアの数)
// O (N log N) (N: 順列の最大値)
template<typename T>
T GetInversionCnt(const vector<T>& p) {
    T ret = 0;
    T max_val = 0;
    for(auto& val : p) { max_val = max(max_val, val); }
    BITree<T> bit(max_val);    // 以左に現れた数を BIT で管理
    for(int i = 0; i < p.size(); ++i) {
        ret += bit.Sum(p[i] + 1, max_val);  // 自分より大きいものを数える
        bit.Add(p[i], 1);   // 現れた数を更新
    }
    return ret;
}

// 2 つの順列の転倒距離を求める
// 転倒距離：同じサイズ N の順列 X と Y で順番が入れ替わっている数字のペアの数
// X か Y のどちらかが (1, 2, 3 .., N) なら、転倒距離はもう一方の転倒数
// O(N log N)
template<typename T>
T GetInversionDist(const vector<T>& v1, const vector<T>& v2) {
    assert(v1.size() == v2.size());
    vector<T> val_to_ind, comp;
    val_to_ind.assign(v1.size() + 1, 0);
    for(int i = 0; i < v1.size(); ++i) {
        val_to_ind[v1[i]] = i + 1;
    }
    for(int i = 0; i < v2.size(); ++i) {
        comp.push_back(val_to_ind[v2[i]]);
    }
    return GetInversionCnt(comp);
}

// b とかぶらない数にする
static inline ll change_w(ll w) { return w + N; }

enum CostType { CostB = 0, CostW };

// B を [1,i] , W を [1,j] 個既に置いているときに黒の i+1 を置いた時の転倒数
ll cost(ll i, ll j, ll type) {
#if 0
    vector<ll> v1, v2;
    // [1,i], [1,j] の置き方は合わせる
    for(ll b = 1; b <= i; ++b) {
        v1.push_back(b);
        v2.push_back(b);
    }
    for(ll w = 1; w <= j; ++w) {
        v1.push_back(change_w(w));
        v2.push_back(change_w(w));
    }
    if(type == CostB) { v1.push_back(i+1); }
    else { v1.push_back(change_w(j+1)); }

    // 残りを置いていく
    REP(ind, 2 * N) {
        if(C[ind] == 'B') {
            if(type == CostB) {
                if(A[ind] == i + 1) { v2.push_back(A[ind]); }
                else if(A[ind] > i + 1) { v1.push_back(A[ind]); v2.push_back(A[ind]); }
            } else {
                if(A[ind] > i) { v1.push_back(A[ind]); v2.push_back(A[ind]); }
            }
        } else {
            if(type == CostB) {
                if(A[ind] > j) { v1.push_back(change_w(A[ind])); v2.push_back(change_w(A[ind])); }
            } else {
                if(A[ind] == j + 1) { v2.push_back(change_w(A[ind])); }
                else if(A[ind] > j + 1) { v1.push_back(change_w(A[ind])); v2.push_back(change_w(A[ind])); }
            }
        }
    }
    ll ret = GetInversionDist(v1, v2);
#else

    // 現在の i+1/j+1 の位置 から左にある i と j より大きいものの数
    ll ret = 0;
    ll cur = 0;
    for(cur = 0; cur < 2 * N; ++cur) {
        if((type == CostB && C[cur] == 'B' && A[cur] == i+1) ||
           (type == CostW && C[cur] == 'W' && A[cur] == j+1)) {
            break;
        }
    }
    BITree<ll> bit_B(N), bit_W(N);    // 以左に現れた数を BIT で管理
    for(ll ind = 0; ind < cur; ++ind) {
        // 現れた数を更新
        if(C[ind] == 'B') { bit_B.Add(A[ind], 1); }
        else { bit_W.Add(A[ind], 1); }

    }
    if(type == CostB) {
        ret += bit_B.Sum(i+2, N);
        ret += bit_W.Sum(j+1, N);
    }
    else {
        ret += bit_B.Sum(i+1, N);
        ret += bit_W.Sum(j+2, N);
    }
#endif
    //DBG("i: %lld j: %lld type: %c ret: %lld\n", i, j, (type == CostB) ? 'B' : 'W', ret);
    return ret;
}

ll dp[MAX_N][MAX_N] = {};

// B を [1,i] 個, W を [1,j] 個置いた時の最小転倒数
ll dfs(ll i, ll j) {
    if(i <= 0 && j <= 0) {
        dp[0][0] = 0;
        return 0;
    }
    if(dp[i][j] != -1) { return dp[i][j]; }
    ll cand1 = INF, cand2 = INF;
    if(i > 0) { cand1 = dfs(i-1, j) + cost(i-1, j, CostB); }
    if(j > 0) { cand2 = dfs(i, j-1) + cost(i, j-1, CostW); }
    dp[i][j] = min(cand1, cand2);
    return dp[i][j];
}

signed main()
{
    cin >> N;
    REP(i, 2 * N) { cin >> C[i] >> A[i]; }
    MINUS(dp);
    printf("%lld\n", dfs(N, N));
    return 0;
}