import fractions import itertools def read_data(): N = int(input()) A = int(input()) Bs = list(map(int, input().split())) C = int(input()) Ds = list(map(int, input().split())) return N, A, Bs, C, Ds def solve(N, A, Bs, C, Ds): ''' A > C と仮定する。(そうでないときは、Bs, Ds の値の正負を反転すればよい。) Bs, Ds の最小公倍数で1ブロック分とする。これの繰り返しパターンの計算を避けるため、 まずは、これを切り出す。 残りの部分について、Bsの繰り返し回数 + Bsの余り、とDsの繰り返し回数_Dsの余り を処理する。 Bsの余り部分は、Bsから大きいのを持ってくればよい。 Dsの余り部分は、Dsから小さいのを持ってくればよい。 Bs 1つ目について、Ds 何個か + Ds 先頭いくつか とする。先頭いくつかを選ぶパターンを全て総当たりする。 Bs 2つ目について、Ds 残りいくつか+Ds何個か+Ds先頭いくつか とする。残りいくつかは、その前のステップで決まる。Ds先頭いくつかを先ほどと同じように総当たりする。 ''' Bs.sort(reverse=True) Ds.sort() minB = Bs[-1] maxD = Ds[-1] if minB > maxD: return N maxB = Bs[0] minD = Ds[0] if maxB <= minD: return 0 lcm = A * C // fractions.gcd(A, C) blocks, residue = divmod(N, lcm) result = 0 if blocks: result += blocks * dfs(lcm, A, Bs, C, Ds) if residue: result += dfs(residue, A, Bs, C, Ds) return result def dfs(N, A, Bs, C, Ds): if A >= C: return dfsAC(N, A, Bs, C, Ds, []) else: return dfsCA(N, A, Bs, C, Ds, []) def dfsCA(N, A, Bs, C, Ds, B_head): ''' A < C , N <= lcm(A, C) は保証されているとする。 ''' if N == 0: return 0 # 0 < N <= A < C, N <= len_head となるよう前処理 if N < C: C = N Ds = Ds[:N] len_head = len(B_head) if N < len_head: len_head = N B_head = B_head[:] B_head.sort(reverse=True) B_head = B_head[:N] # C = len_head + n_body * A + len_tail と分解する。 n_body, len_tail = divmod(C - len_head, A) Bs_head_body = B_head + Bs * n_body Bs_head_body.sort(reverse=True) # B_tail とつなげた後にもsortするが、いちどやっておく。 # 最後の1区画のときは、B_tail として、Bsの大きいのを与えて計算すればよい。 if N == C: return count_win(Bs_head_body + Bs[:len_tail], Ds) # B_tail を総当たりで試す。 record = 0 for B_tail, B_new_head in generate_tails(Bs, A, len_tail): score = count_win(Bs_head_body + B_tail, Ds) score += dfsCA(N - A, A, Bs, C, Ds, B_new_head) if record < score: record = score if record == N: break # 全勝なら探索打ち切り return record def dfsAC(N, A, Bs, C, Ds, D_head): ''' A >= C , N <= lcm(A, C) は保証されているとする。 ''' if N == 0: return 0 # 0 < N <= C <= A, N <= len_head となるよう前処理 if N < A: A = N Bs = Bs[:N] len_head = len(D_head) if N < len_head: len_head = N D_head = D_head[:] D_head.sort() D_head = D_head[:N] # A = len_head + n_body * C + len_tail と分解する。 n_body, len_tail = divmod(A - len_head, C) Ds_head_body = D_head + Ds * n_body Ds_head_body.sort() # D_tail とつなげた後にもsortするが、いちどやっておく。 # 最後の1区画のときは、D_tail として、Ds の小さいのを与えて計算すればよい。 if N == A: return count_win(Bs, Ds_head_body + Ds[:len_tail]) # D_tail を総当たりで試す。 record = 0 for D_tail, D_new_head in generate_tails(Ds, C, len_tail): score = count_win(Bs, Ds_head_body + D_tail) score += dfsAC(N - A, A, Bs, C, Ds, D_new_head) if record < score: record = score if record == N: break # 全勝なら探索打ち切り return record def generate_tails(Ds, C, len_tail): '''長さ C のリスト Ds から、長さ len_tail のリストD_tail (とその残り)を列挙する。 現状では、Ds の中に、同じ数字がある場合は、無駄な列挙が生じてしまう。 ''' for idxs_tail in itertools.combinations(range(C), len_tail): D_tail = [Ds[i] for i in idxs_tail] D_head = [d for i, d in enumerate(Ds) if i not in idxs_tail] yield D_tail, D_head def count_win(Bs, Ds): ''' Bs は降順、 Ds は整列されているとは限らない。 Bs と Ds のリストの長さは同じとなっている。 Bs, Ds を適当に並び替えて、 bi > di となる個数の最大値を返す。 ''' Ds.sort() Bs = Bs[:] Bs.sort(reverse=True) wins = 0 for d in Ds: while Bs[-1] <= d: del Bs[-1] if not Bs: return wins wins += 1 del Bs[-1] if not Bs: return wins return wins if __name__ == '__main__': N, A, Bs, C, Ds = read_data() print(solve(N, A, Bs, C, Ds))