#include using namespace std; #define rep(i, n) for(int i=0; i #include //vectorの中身を空白区切りで出力 template void printv(vector v) { for (int i = 0; i < v.size(); i++) { cout << v[i]; if (i < v.size() - 1) { cout << " "; } } cout << endl; } //vectorの中身を改行区切りで出力 template void print1(vector v) { for (auto x : v) { cout << x << endl; } } //二次元配列を出力 template void printvv(vector> vv) { for (vector v : vv) { printv(v); } } //vectorを降順にソート template void rsort(vector& v) { sort(v.begin(), v.end()); reverse(v.begin(), v.end()); } //昇順priority_queueを召喚 template struct rpriority_queue { priority_queue, greater> pq; void push(T x) { pq.push(x); } void pop() { pq.pop(); } T top() { return pq.top(); } size_t size() { return pq.size(); } bool empty() { return pq.empty(); } }; //mod mod下で逆元を算出する //高速a^n計算(mod ver.) ll power(ll a, ll n) { if (n == 0) { return 1; } else if (n % 2 == 0) { ll x = power(a, n / 2); x *= x; x %= mod; return x; } else { ll x = power(a, n - 1); x *= a; x %= mod; return x; } } //フェルマーの小定理を利用 ll modinv(ll p) { return power(p, mod - 2) % mod; } //Mexを求める struct Mex { map mp; set s; Mex(int Max) { for (int i = 0; i <= Max; i++) { s.insert(i); } } int _mex = 0; void Input(int x) { mp[x]++; s.erase(x); if (_mex == x) { _mex = *begin(s); } } void Remove(int x) { if (mp[x] == 0) { cout << "Mex ERROR!: NO VALUE WILL BE REMOVED" << endl; } mp[x]--; if (mp[x] == 0) { s.insert(x); if (*begin(s) == x) { _mex = x; } } } int mex() { return _mex; } }; //条件分岐でYes/Noを出力するタイプのやつ void YN(bool true_or_false) { cout << (true_or_false ? "Yes" : "No") << endl; } //最大公約数(ユークリッドの互除法) ll gcd(ll a, ll b) { if (b > a) { swap(a, b); } while (a % b != 0) { ll t = a; a = b; b = t % b; } return b; } //最小公倍数(gcdを定義しておく) ll lcm(ll a, ll b) { ll g = gcd(a, b); ll x = (a / g) * b; return x; } struct UnionFind { vector par; UnionFind(int N) { rep(i, N) { par.push_back(i); } } int root(int x) { if (par[x] == x) { return x; } else { return par[x] = root(par[x]); } } bool isSame(int x, int y) { return root(x) == root(y); } void Union(int x, int y) { if (!isSame(x, y)) { int rx = root(x), ry = root(y); if (rx > ry) { par[rx] = ry; } else { par[ry] = rx; } } } }; //最大流問題を解く構造体(Ford-Fulkerson法.O(FE)) struct maxflow { struct Edge { int to, rev; ll capacity, init_capacity; Edge(int _to, int _rev, ll _capacity) :to(_to), rev(_rev), capacity(_capacity), init_capacity(_capacity) {}; }; vector> Graph; maxflow(int MAX_V) { Graph.assign(MAX_V, {}); } void input(int from, int to, ll capacity) { int e_id = Graph[from].size(); int r_id = Graph[to].size(); Graph[from].push_back(Edge(to, r_id, capacity)); Graph[to].push_back(Edge(from, e_id, 0)); } Edge& rev_Edge(Edge& edge) { return Graph[edge.to][edge.rev]; } vector visited; ll dfs(int now, int g, ll flow) { visited[now] = true; if (now == g) { return flow; } else { ll f = 0; ll res_flow = flow; for (Edge& edge : Graph[now]) { if (!visited[edge.to] && edge.capacity > 0) { ll f_delta = dfs(edge.to, g, min(res_flow, edge.capacity)); edge.capacity -= f_delta; rev_Edge(edge).capacity += f_delta; f += f_delta; res_flow -= f_delta; if (res_flow == 0) { break; } } } return f; } } void flowing(int s, int g, ll init_flow = INF) { bool cont = true; while (cont) { visited.assign(Graph.size(), false); ll flow = dfs(s, g, init_flow); init_flow -= flow; if (flow == 0) { cont = false; } } } ll get_flow(int g) { ll flow = 0; for (Edge& edge : Graph[g]) { Edge& rev_edge = rev_Edge(edge); ll tmp_flow = rev_edge.init_capacity - rev_edge.capacity; if (tmp_flow > 0) { flow += tmp_flow; } } return flow; } vector> flowing_edges() { vector> vec; rep(from, Graph.size()) { for (Edge& edge : Graph[from]) { ll flow = edge.init_capacity - edge.capacity; if (flow > 0) { vec.push_back({ from,edge.to,flow }); } } } return vec; } vector min_cut(int s) { vector check(Graph.size(), false); queue q; q.push(s); check[s] = true; while (!q.empty()) { int now = q.front(); q.pop(); for (Edge& edge : Graph[now]) { if (edge.capacity > 0 && !check[edge.to]) { check[edge.to] = true; q.push(edge.to); } } } return check; } vector> min_cut_edges(int s) { vector cut = min_cut(s); vector> vec; for (int from = 0; from < Graph.size(); from++) { if (cut[from]) { for (Edge& edge : Graph[from]) { if (!cut[edge.to] && edge.init_capacity > 0) { vec.push_back({ from,edge.to,edge.init_capacity }); } } } } return vec; } void reset() { for (int from = 0; from < Graph.size(); from++) { for (Edge& edge : Graph[from]) { edge.capacity = edge.init_capacity; } } } }; //Dinic法でのmax-flow。最大マッチングなど辺のキャパシティが小さい場合には高速 struct Dinic { struct Edge { int to, rev; ll capacity, init_capacity; ld cost; Edge(int _to, int _rev, ll _capacity,ld _cost) :to(_to), rev(_rev), capacity(_capacity),init_capacity(_capacity),cost(_cost) {}; }; vector> Graph; Edge& rev_Edge(Edge& edge) { return Graph[edge.to][edge.rev]; } vector level,itr; Dinic(int MAX_V) { Graph.assign(MAX_V, {}); } void input(int _from, int _to, ll _capacity,ld _cost) { int e_id = Graph[_from].size(), r_id = Graph[_to].size(); Graph[_from].push_back(Edge(_to, r_id, _capacity,_cost)); Graph[_to].push_back(Edge(_from, e_id, 0LL,_cost)); } void bfs(int s, int g, ld val) { level.assign(Graph.size(), -1); level[s] = 0; queue q; q.push(s); while (!q.empty()) { int now = q.front(); q.pop(); if (now == g) { continue; } for (Edge &e : Graph[now]) { if (level[e.to] == -1 && e.capacity > 0 && e.cost<=val) { level[e.to] = level[now] + 1; q.push(e.to); } } } } ll dfs(int now, int g, ll flow, ld val) { if (now == g) { return flow; } else if (level[now] >= level[g]) { return 0; //gよりも深い場所に行こうとしたら終わり。flow=0を返す } else { ll res_flow = flow; ll f = 0; for (int &i = itr[now]; i < Graph[now].size(); i++) { Edge& edge = Graph[now][i]; if (level[edge.to] == level[now] + 1 && edge.capacity > 0 && edge.cost<=val) { ll f_delta = dfs(edge.to, g, min(res_flow, edge.capacity), val); edge.capacity -= f_delta; rev_Edge(edge).capacity += f_delta; res_flow -= f_delta; f += f_delta; if (res_flow == 0) { break; } } } return f; //行先が無い場合はflow=0を返す } } void flowing(int s, int g, ll init_flow = INF, ld val=0) { bool cont1 = true; while (cont1) { bfs(s, g,val); if (level[g] == -1) { cont1 = false; } else { bool cont2 = true; while (cont2) { itr.assign(Graph.size(), 0); ll flow = dfs(s, g, init_flow,val); init_flow -= flow; if (flow == 0) { cont2 = false; } } } } } ll get_flow(int g) { ll flow = 0; for (Edge& edge : Graph[g]) { flow += max(0LL, rev_Edge(edge).init_capacity - rev_Edge(edge).capacity); } return flow; } vector> flowing_edges(){ vector> vec; for (int from = 0; from < Graph.size(); from++) { for (Edge& edge : Graph[from]) { if (edge.init_capacity - edge.capacity > 0) { vec.push_back({ from,edge.to,edge.init_capacity - edge.capacity }); } } } return vec; } vector min_cut(int s) { vector check(Graph.size(), false); queue q; q.push(s); check[s] = true; while (!q.empty()) { int now = q.front(); q.pop(); for (Edge& edge : Graph[now]) { if (edge.capacity > 0 && !check[edge.to]) { check[edge.to] = true; q.push(edge.to); } } } return check; } vector> min_cut_edges(int s) { vector cut = min_cut(s); vector> vec; for (int from = 0; from < Graph.size(); from++) { if (cut[from]) { for (Edge& edge : Graph[from]) { if (!cut[edge.to] && edge.init_capacity > 0) { vec.push_back({ from,edge.to,edge.init_capacity }); } } } } return vec; } void reset() { for (int from = 0; from < Graph.size(); from++) { for (Edge& edge : Graph[from]) { edge.capacity = edge.init_capacity; } } } }; int main() { int N; cin >> N; map>> dp; dp[0][0][0] = 0; rep(i, N*2) { char c; ll L, R; cin >> c >> L >> R; for (auto &p : dp[i]) { for (auto &q : p.second) { int l = p.first; int r = q.first; ll m = q.second; if (c == ')') { if (r == 0) { dp[i + 1][l + 1][0] = max(dp[i + 1][l + 1][0], m + max(L, R)); } else { if (r > 0) { dp[i + 1][l][r - 1] = max(dp[i + 1][l][r - 1], m + R); } dp[i + 1][l + 1][r] = max(dp[i + 1][l + 1][r], m + L); } } else { if (l == 0) { dp[i + 1][0][r + 1] = max(dp[i+1][0][r + 1], m + max(L, R)); } else { if (l > 0) { dp[i + 1][l - 1][r] = max(dp[i + 1][l - 1][r], m + L); } dp[i + 1][l][r + 1] = max(dp[i + 1][l][r + 1], m + R); } } } } } cout << dp[N*2][0][0] << endl; }