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)

use std::io::*;
use std::str::FromStr;
use std::collections::HashMap;

#[allow(dead_code)]
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

#[allow(dead_code)]
#[derive(Clone)]
struct FenwickTree {
    seq: Vec<i64>,
}
#[allow(dead_code)]
impl FenwickTree {
    fn new(n: usize) -> FenwickTree {
        FenwickTree {
            seq: vec![0; n + 2],
        }
    }
    fn add(&mut self, index: usize, value: i64) {
        let mut index = (index + 1) as i32;
        while (index as usize) < self.seq.len() {
            self.seq[index as usize] += value;
            index += index & -index;
        }
    }
    // inclusive
    fn sum(&self, index: usize) -> i64 {
        let mut ret = 0;
        let mut index = (index + 1) as i32;
        while index > 0 {
            ret += self.seq[index as usize];
            index -= index & -index;
        }
        ret
    }
}

struct Solver {
    n: usize,
    seq: Vec<(usize, char)>,
    rev_map: HashMap<(usize, char), usize>,
    white_counts: Vec<FenwickTree>,
    black_counts: Vec<FenwickTree>,
    memo: Vec<Vec<i64>>,
}

impl Solver {
    fn new() -> Solver {
        let n = read::<usize>();
        let mut seq = vec![(0, 'W'); 2 * n];
        let mut rev_map = HashMap::<(usize, char), usize>::new();
        let mut white_counts = vec![FenwickTree::new(2 * n + 10); n];
        let mut black_counts = vec![FenwickTree::new(2 * n + 10); n];
        for i in 0..2 * n {
            seq[i].1 = read::<String>().chars().collect::<Vec<char>>()[0];
            seq[i].0 = read::<usize>() - 1;
            rev_map.insert(seq[i], i);
            for j in seq[i].0..n {
                if seq[i].1 == 'W' {
                    white_counts[j].add(i, 1);
                } else {
                    black_counts[j].add(i, 1);
                }
            }
        }
        // println!("{:?}", rev_map);
        let memo = vec![vec![1 << 60; n + 1]; n + 1];
        Solver {
            n: n,
            seq: seq,
            memo: memo,
            rev_map: rev_map,
            white_counts: white_counts,
            black_counts: black_counts,
        }
    }
    fn dist(&self, index: usize, white: usize, black: usize) -> i64 {
        let mut ret = index as i64;
        if white > 0 {
            // println!("{}", self.white_counts[white - 1].sum(index));
            ret -= self.white_counts[white - 1].sum(index);
        }
        if black > 0 {
            // println!("{}", self.black_counts[black - 1].sum(index));
            ret -= self.black_counts[black - 1].sum(index);
        }
        // println!("{} {} {} {}", index, ret, white, black);
        assert!(ret >= 0);
        ret
    }
    fn calc(&mut self, white: usize, black: usize) -> i64 {
        if white == self.n && black == self.n {
            return 0;
        }
        if self.memo[white][black] != (1 << 60) {
            return self.memo[white][black];
        }
        let mut ret = 1 << 60;
        if white != self.n {
            let &index = self.rev_map.get(&(white, 'W')).unwrap();
            let nret = self.dist(index, white, black) + self.calc(white + 1, black);
            ret = std::cmp::min(ret, nret);
        }
        if black != self.n {
            let &index = self.rev_map.get(&(black, 'B')).unwrap();
            let nret = self.dist(index, white, black) + self.calc(white, black + 1);
            ret = std::cmp::min(ret, nret);
        }
        self.memo[white][black] = ret;
        ret
    }
    fn solve(&mut self) {
        let ans = self.calc(0, 0);
        println!("{}", ans);
    }
}

fn main() {
    let mut solver = Solver::new();
    solver.solve();
}