//#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <queue>
#include <algorithm>
#include <sstream>
#include <vector>
#include <math.h>
#include <set>
#include <map>
#include <numeric>
#include <bitset>
#include <iomanip>
#include <cctype>
#include <cstdlib>      // srand,rand


using namespace std;
#define ll long long

#define modd 1000000007
#define INF 1000000000000000000ll


typedef pair<long long, long long> pl;



typedef string::const_iterator State;
class ParseError {};








class UnionFind {
public:
	vector <ll> par;
	vector <ll> siz;

	// Constructor
	UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
		for (ll i = 0; i < sz_; ++i) par[i] = i;
	}
	void init(ll sz_) {
		par.resize(sz_);
		siz.assign(sz_, 1LL);  // resize だとなぜか初期化されなかった
		for (ll i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
	}

	// Member Function
	// Find
	ll root(ll x) { // 根の検索
		while (par[x] != x) {
			x = par[x] = par[par[x]]; // x の親の親を x の親とする
		}
		return x;
	}

	// Union(Unite, Merge)
	bool merge(ll x, ll y) {
		x = root(x);
		y = root(y);
		if (x == y) return false;

		// merge technique（データ構造をマージするテク．小を大にくっつける）
		if (siz[x] < siz[y]) swap(x, y);
		siz[x] += siz[y];
		par[y] = x;
		return true;
	}



	bool issame(ll x, ll y) { // 連結判定
		return root(x) == root(y);
	}

	ll size(ll x) { // 素集合のサイズ
		return siz[root(x)];
	}


};

/*
struct SegmentTree {
private:
	ll n;
	vector<ll> node;

public:
	// 元配列 v をセグメント木で表現する
	SegmentTree(vector<ll> v) {
		// 最下段のノード数は元配列のサイズ以上になる最小の 2 冪 -> これを n とおく
		// セグメント木全体で必要なノード数は 2n-1 個である
		ll sz = v.size();
		n = 1; while (n < sz) n *= 2;
		node.resize(2 * n - 1, INF);

		// 最下段に値を入れたあとに、下の段から順番に値を入れる
		// 値を入れるには、自分の子の 2 値を参照すれば良い
		for (ll i = 0; i < sz; i++) node[i + n - 1] = v[i];
		for (ll i = n - 2; i >= 0; i--) node[i] = min(node[2 * i + 1], node[2 * i + 2]);
	}


	void update(ll x, ll val) {
		// 最下段のノードにアクセスする
		x += (n - 1);

		// 最下段のノードを更新したら、あとは親に上って更新していく
		node[x] = val;
		while (x > 0) {
			x = (x - 1) / 2;
			node[x] = min(node[2 * x + 1], node[2 * x + 2]);
		}
	}

};
*/


long long N, M, K, a, b, c,d,e, H, W, L, T;
ll A[2][300005] = {};
ll B[300005] = {};
ll C[300005] = {};
bool f, ff;
string S[200000];
string SS;
set <long long>sll;
pl bufpl;
vector <long long>vl[600005];
vector <long long>vll;
vector <pl>vpl;
vector <string> vs;
set<ll> llset;
multiset<ll> llmset;
queue<ll> ql;



struct ST
{
	ll first;
	ll second;
	ll kaisuu;


	bool operator<(const ST& another) const
	{
		return first < another.first;//比較
	};

};



/*vector <ST> vst;
ST st[200005];
ST bufst;
bitset<5000> bits;*/


long long modinv(long long aa, long long mm) {
	long long bb = mm, uu = 1, vv = 0;
	while (bb) {
		long long tt = aa / bb;
		aa -= tt * bb; swap(aa, bb);
		uu -= tt * vv; swap(uu, vv);
	}
	uu %= mm;
	if (uu < 0) uu += mm;
	return uu;
}


ll minn, maxx;
double ansa;

ll zettai(ll aa) {

	if (aa < 0) {
		aa *= -1;
	}
	return aa;

}



double ab[20000];

ll ha[2];

ll x, y;

struct edge {
	ll from;
	ll to;
	ll cost;
};


/*
ll V, E, d[300000];
edge es[300000];
bool fa[5000][5000];
bool ffa[5000];

bool has_negative_loop(ll s) {
	fill(d, d + V, 50000000000000000);
	d[s] = 0;
	for (ll i = 0; i <=2* V+1; i++) {
		for (ll j = 0; j < E; j++) {
			edge e = es[j];
			if (d[(int)e.to] > d[(int)e.from] + e.cost) {
				d[(int)e.to] = d[(int)e.from] + e.cost;
				if (i >= V+1 && fa[(int)e.to][V-1]==true &&fa[0][(int)e.from] == true) {
					return true;
				}
			}
		}
	}
	return false;
}
*/


bool ruiseki[2][2500];
ll AA[2][2001][2][2001];
ll iti[2][2001];

ll dp[4002][2002];

int main() {
	cin >> N;

	for (int i = 0; i < 4001; i++) {
		for (int j = 0; j < 2001; j++) {
			dp[i][j] = INF/2;
		}
	}

	for (int i = 0; i < 2 * N; i++) {
		cin >> S[i] >> A[1][i];

		if (S[i][0] == 'W') {
			A[0][i] = 0;
		}
		else {
			A[0][i] = 1;
		}

		iti[A[0][i]][A[1][i]] = i;

	}

	for (int i = 0; i < 2 * N; i++) {

		for (int j = 0; j <= N; j++) {
			ruiseki[0][j] = false;
			ruiseki[1][j] = false;
		}

		for (int j = i + 1; j < 2 * N; j++) {
			ruiseki[A[0][j]][A[1][j]] = true;
		}

		AA[A[0][i]][A[1][i]][0][1] = 0;
		AA[A[0][i]][A[1][i]][1][1] = 0;

		if (ruiseki[0][1])AA[A[0][i]][A[1][i]][0][1] = 1;
		if (ruiseki[1][1])AA[A[0][i]][A[1][i]][1][1] = 1;

		for (int j = 2; j <= N; j++) {
			if (ruiseki[0][j]) {
				AA[A[0][i]][A[1][i]][0][j] = AA[A[0][i]][A[1][i]][0][j - 1] + 1;
			}
			else {
				AA[A[0][i]][A[1][i]][0][j] = AA[A[0][i]][A[1][i]][0][j - 1];
			}

			if (ruiseki[1][j]) {
				AA[A[0][i]][A[1][i]][1][j] = AA[A[0][i]][A[1][i]][1][j - 1] + 1;
			}
			else {
				AA[A[0][i]][A[1][i]][1][j] = AA[A[0][i]][A[1][i]][1][j - 1];
			}

		}

	}


	dp[1][0] = iti[1][1];
	dp[1][1] = iti[0][1];

	for (int i = 1; i < 2 * N; i++) {
		a = min(N, (ll)i+1);
		b = max((ll)0, (ll)(i + 1- N));

		for (int j = b; j <= a; j++) {
			if (i + 1 - j <= N && i+1-j>0) {

				d = 0;
				if (i + 1 - j - 1 >= 0) {
					d = AA[1][i + 1 - j][1][i + 1 - j -1];
					//cout << AA[1][i + 1 - j][1][i + 1 - j - 1] << ' '<< AA[1][i + 1 - j][1][i + 1 - j - 0] << endl;
				}

				e = 0;

				if (j >= 0) {
					e = AA[1][i + 1 - j][0][j];
				}

				c = dp[i + 1 - 1][j] + iti[1][i + 1 - j] + d + e;

				c -= i;


				dp[i + 1][j] = min(dp[i + 1][j], c);

			}

		}

		a = min(N, (ll)i + 1);
		b = max((ll)1, (ll)(i + 1 - N));

		for (int j = b; j <= a; j++) {

			d = 0;
			if (i +1 - j >= 0) {
				d = AA[0][j][1][i + 1 - j];
			}

			e = 0;

			if (j - 1 >= 0) {
				e = AA[0][j][0][j - 1];
			}

			c = dp[i +1 - 1][j-1] + iti[0][j] + d + e;

			c -= i;

			if (c < 0) {
				c = c;
			}


			dp[i+1][j] = min(dp[i+1][j], c);



		}

	}




	cout << dp[2 * N][N] << endl;

	//cout << fixed << setprecision(10) << ansa << endl;
	return 0;



}


Measured memory_bytes: 209280