#include #include #include #include #include #include #include #include #include // require sort next_permutation count __gcd reverse etc. #include // require abs exit atof atoi #include // require scanf printf #include #include // require accumulate #include // require fabs #include #include #include #include // require setw #include // require stringstream #include // require memset #include // require tolower, toupper #include // require freopen #include // require srand #define rep(i,n) for(int i=0;i<(n);i++) #define ALL(A) A.begin(), A.end() #define INF 1<<28 using namespace std; typedef long long ll; typedef pair P; /* yukicoder: No. 161 制限ジャンケン 最大費用流(?) 最大費用流 := 最大費用 - 最小費用流 最大費用 := 3*|S| よって 最小費用流を求める. --> G ----> g / \\ / \ / \ /\ \ S ---> C ----> c --> T \ / \/ / \ / / \ / --> P ----> p G : cap : G C : cap : C P : cap : P g : cap : g c : cap : c p : cap : p S -> G : cost : 0 S -> C : cost : 0 S -> P : cost : 0 G -> g : cost : 3 - 1 G -> c : cost : 3 - 3 G -> p : cost : 3 - 0 C -> g : cost : 3 - 0 C -> c : cost : 3 - 1 C -> p : cost : 3 - 3 g -> T : cost : 0 c -> T : cost : 0 c -> T : cost : 0 */ const int MAX_V = 3 + 3 + 2; // 辺を表す構造体 (行き先、容量、コスト、逆辺) struct edge{ int to, cap, cost, rev; }; int V; // 頂点数 vector G[MAX_V]; // グラフの隣接リスト表現 int dist[MAX_V]; // 最短距離 int prevv[MAX_V], preve[MAX_V]; // 直前の頂点と辺 // from から to へ向かう容量 cap の辺をグラフに追加する void add_edge (int from, int to, int cap, int cost ){ G[from].push_back ((edge){to, cap, cost, G[to].size() } ); G[to].push_back ((edge){from, 0, -cost, G[from].size() -1}); } // s から t への流量 f の最小費用流を求める // 流せない場合は -1 を返す int min_cost_flow (int s, int t, int f ){ int res = 0; while (f > 0 ){ // ベルマンフォード法により、s-t 間最短路を求める fill (dist, dist+V, INF ); dist[s] = 0; bool update = true; while (update ){ update = false; rep (v, V ){ if (dist[v] == INF ) continue; rep (i, G[v].size() ){ edge &e = G[v][i]; if (e.cap > 0 && dist[e.to] > dist[v] + e.cost ){ dist[e.to] = dist[v] + e.cost; prevv[e.to] = v; preve[e.to] = i; update = true; } // end if } // end rep } // end rep } // end while if (dist[t] == INF ){ // これ以上流せない return -1; } // end if // s-t 間最短路に沿って目一杯流す int d = f; for (int v = t; v != s; v = prevv[v] ){ d = min (d, G[prevv[v]][preve[v]].cap ); } // end for f -= d; res += d*dist[t]; for (int v = t; v != s; v = prevv[v] ){ edge &e = G[prevv[v]][preve[v]]; e.cap -= d; G[v][e.rev].cap += d; } // end for } // end while return res; } int main() { ios_base::sync_with_stdio(0); int G, C, P; cin >> G >> C >> P; string s; cin >> s; int g = (int)count (ALL (s), 'G' ); int c = (int)count (ALL (s), 'C' ); int p = (int)count (ALL (s), 'P' ); V = MAX_V; int S = 0, T = V - 1; add_edge (S, 1, G, 0 ); // S -> G add_edge (S, 2, C, 0 ); // S -> C add_edge (S, 3, P, 0 ); // S -> P add_edge (1, 4, g, 3-1 ); // G -> g add_edge (1, 5, c, 3-3 ); // G -> c add_edge (1, 6, p, 3-0 ); // G -> p add_edge (2, 4, g, 3-0 ); // C -> g add_edge (2, 5, c, 3-1 ); // C -> c add_edge (2, 6, p, 3-3 ); // C -> p add_edge (3, 4, g, 3-3 ); // P -> g add_edge (3, 5, c, 3-0 ); // P -> c add_edge (3, 6, p, 3-1 ); // P -> p add_edge (4, T, g, 0 ); // g -> T add_edge (5, T, c, 0 ); // c -> T add_edge (6, T, p, 0 ); // p -> T int ans = min_cost_flow (S, T, G + C + P ); int res = 3*(int)s.length() - ans; cout << res << endl; return 0; }