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 Rust (1.15.1) (judge verdict: Accepted)

#![allow(unused_imports)]
#![allow(non_snake_case)]

use procon::*;
use std::collections::*;
use std::ops::*;
use std::*;

#[derive(PartialEq, Clone, Copy, Debug)]
enum Color {
    W,
    B,
}

#[derive(PartialEq, Clone, Debug)]
struct Ball {
    pub color: Color,
    pub rank: usize,
}

pub fn min(l: usize, r: usize) -> usize {
    if l < r {
        l
    } else {
        r
    }
}

pub fn main() {
    let N: usize = read_line().parse().unwrap();
    let balls = (0..(N * 2))
        .map(|_| {
            let w: Vec<String> = read_words();
            let c = if w[0] == "W" { Color::W } else { Color::B };
            let r = w[1].parse().unwrap();
            Ball { color: c, rank: r }
        })
        .collect::<Vec<_>>();

    let count = {
        let f = |color: Color| {
            // ks[i][rank]: (ある色について) 位置 i より右にある rank 以下の玉の個数
            let mut ks = (0..(2 * N)).map(|_| vec![0; N + 1]).collect::<Vec<_>>();
            for rank in 1..N + 1 {
                let mut k = 0;
                for i in (0..(2 * N)).rev() {
                    if balls[i].color == color && balls[i].rank <= rank {
                        k += 1;
                    }
                    ks[i][rank] = k;
                }
            }
            ks
        };

        let ws = f(Color::W);
        let bs = f(Color::B);

        let g = |color: Color| {
            let mut indexes = vec![0; N + 1];
            for i in 0..(2 * N) {
                if balls[i].color == color {
                    indexes[balls[i].rank] = i;
                }
            }
            indexes
        };

        let wi = g(Color::W);
        let bi = g(Color::B);

        move |next: &Ball, w: usize, b: usize| {
            let i = if next.color == Color::W {
                wi[next.rank]
            } else {
                bi[next.rank]
            };
            ws[i][w] + bs[i][b]
        }
    };

    let mut dp = vec![vec![std::usize::MAX; N + 1]; N + 1];
    dp[0][0] = 0;

    for w in 0..N + 1 {
        for b in 0..N + 1 {
            // 次が W(w+1) のケース
            // 1以上w以下のボールが左側に配置されている
            // これらのうちもともと W(w+1) より右側にあったものの数が転倒数
            if w + 1 <= N {
                let ball = &Ball {
                    color: Color::W,
                    rank: w + 1,
                };
                let k1 = count(ball, w, b);
                dp[w + 1][b] = min(dp[w + 1][b], dp[w][b] + k1);
            }

            if b + 1 <= N {
                let ball = &Ball {
                    color: Color::B,
                    rank: b + 1,
                };
                let k2 = count(ball, w, b);
                dp[w][b + 1] = min(dp[w][b + 1], dp[w][b] + k2);
            }
        }
    }

    println!("{}", dp[N][N]);
    return;
}

pub mod procon {
    use std;
    use std::collections::*;
    use std::io;
    use std::mem;
    use std::str::FromStr;

    pub fn read_line() -> String {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim_right().to_owned()
    }

    pub fn read_words<T>() -> Vec<T>
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.split_whitespace()
            .map(|word| T::from_str(word).unwrap())
            .collect()
    }

    pub fn read_vec(len: usize) -> Vec<String> {
        let mut vec = Vec::new();
        while vec.len() < len {
            let line = read_line();
            for word in line.split_whitespace() {
                vec.push(word.to_owned());
            }
        }
        assert!(vec.len() == len);
        vec
    }
}