## solution

Fulfill the given orders greedily, in the order of size from small. $O(N)$.

At first, fulfill the orders A, B and C, while it’s possible. Then, fulfill the orders A,B, A,C and B,C, in certain optimal order. There are $3! (= 6)$ ways to fulfill there orders so it can be searched by bruteforce. Finally, fulfill the order A,B,C.

## implementation

#include <iostream>
#include <algorithm>
#include <array>
#define repeat(i,n) for (int i = 0; (i) < (n); ++(i))
template <class T> bool setmax(T & l, T const & r) { if (not (l < r)) return false; l = r; return true; }
template <class T> bool setmin(T & l, T const & r) { if (not (r < l)) return false; l = r; return true; }
using namespace std;
int main() {
int na, nb, nc; cin >> na >> nb >> nc;
int n; cin >> n;

int qa = 0;
int qb = 0;
int qc = 0;
int qab = 0;
int qbc = 0;
int qca = 0;
int qabc = 0;
repeat (i,n) {
string s; cin >> s;
bool a = s.find('A') != string::npos;
bool b = s.find('B') != string::npos;
bool c = s.find('C') != string::npos;
if (    a and not b and not c) ++ qa;
if (not a and     b and not c) ++ qb;
if (not a and not b and     c) ++ qc;
if (    a and     b and not c) ++ qab;
if (not a and     b and     c) ++ qbc;
if (    a and not b and     c) ++ qca;
if (    a and     b and     c) ++ qabc;
}

auto fulfill = [](int & acc, int & na, int & nb, int & nc, bool a, bool b, bool c, int cnt) {
if (a) setmin(cnt, na);
if (b) setmin(cnt, nb);
if (c) setmin(cnt, nc);
acc += cnt;
if (a) na -= cnt;
if (b) nb -= cnt;
if (c) nc -= cnt;
};

int ans = 0;
array<int,3> xs; repeat (i,3) xs[i] = i;
do {
int acc = 0;
int a = na;
int b = nb;
int c = nc;
fulfill(acc, a, b, c, 1, 0, 0, qa);
fulfill(acc, a, b, c, 0, 1, 0, qb);
fulfill(acc, a, b, c, 0, 0, 1, qc);
for (int x : xs) {
if (x == 0) fulfill(acc, a, b, c, 1, 1, 0, qab);
if (x == 1) fulfill(acc, a, b, c, 0, 1, 1, qbc);
if (x == 2) fulfill(acc, a, b, c, 1, 0, 1, qca);
}
fulfill(acc, a, b, c, 1, 1, 1, qabc);
setmax(ans, acc);
} while (next_permutation(xs.begin(), xs.end()));

cout << ans << endl;
return 0;
}