import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Scanner; public class TwoBamboo { /* メモ化用Map */ private static Map calculatedMap; /* 2本の竹をそれぞれ2つのナップサックと考えて、ナップサック問題の動的計画法+メモ化で解く? */ public static void main(String[] args) { Scanner cin = new Scanner(System.in); int d = cin.nextInt(); int[][][] allQuestions = new int[d][2][]; for (int i = 0; i < d; i++) { /* 2本の竹情報 */ allQuestions[i][0] = new int[2]; allQuestions[i][0][0] = cin.nextInt(); allQuestions[i][0][1] = cin.nextInt(); /* 要求数 */ int requestsNum = cin.nextInt(); /* 要求情報 */ allQuestions[i][1] = new int[requestsNum]; for (int j = 0; j < requestsNum; j++) { allQuestions[i][1][j] = cin.nextInt(); } } calculatedMap = new HashMap(); for (int[][] question : allQuestions) { System.out.println(answer(question[0], question[1])); } } /* 各データセット単位で解く */ private static int answer(int[] bamboo, int[] requests) { /* 2本の竹の総和に対し、要求された長さを小さい順に足していく。要求された長さの和が2本の竹の総和を越えたら、以降の要求には絶対に応えられないので無視する。また、長いほうの竹を越える要求も満たせないので無視する */ Arrays.sort(requests); int lengthSum = bamboo[0] + bamboo[1]; int maxRequestLength; int requestSum = 0; for (maxRequestLength = 0; maxRequestLength < requests.length; maxRequestLength++) { requestSum += requests[maxRequestLength]; if (requests[maxRequestLength] > bamboo[1] || requestSum > lengthSum) { break; } } requests = Arrays.copyOf(requests, maxRequestLength); calculatedMap.clear(); return getNum(0, bamboo, requests); } private static int getNum(int currentIndex, int[] bamboo, int[] requests) { /* 最後の要求まで達したなら終了 */ if (currentIndex >= requests.length) { return 0; } /* 竹の長さは変わっている可能性があるのでソートする */ Arrays.sort(bamboo); /* 要求される長さが短い順にソートしているので、長い方の竹からでも切り出せない場合、それ以降切り出すことはできないので終了 */ if (requests[currentIndex] > bamboo[1]) { return 0; } /* メモ化のキーは、現在のインデックスと2本の竹の残りの長さ */ long key = currentIndex * 1000000L * 1000000L + bamboo[0] * 1000000L + bamboo[1]; if (calculatedMap.containsKey(key)) { /* 計算済みなら返却 */ return calculatedMap.get(key); } /* 切らないケース */ int result = getNum(currentIndex + 1, bamboo, requests); /* 長い方から切り出すケース */ int[] cutOfLongBamboo = Arrays.copyOf(bamboo, bamboo.length); cutOfLongBamboo[1] -= requests[currentIndex]; int cutOfLongBambooNum = 1 + getNum(currentIndex + 1, cutOfLongBamboo, requests); if (cutOfLongBambooNum > result) { result = cutOfLongBambooNum; } if (requests[currentIndex] <= bamboo[0]) { int[] cutOfShortBamboo = Arrays.copyOf(bamboo, bamboo.length); cutOfShortBamboo[0] -= requests[currentIndex]; int cutOfShortBambooNum = 1 + getNum(currentIndex + 1, cutOfShortBamboo, requests); if (cutOfShortBambooNum > result) { result = cutOfShortBambooNum; } } calculatedMap.put(key, result); return result; } private static void debug(int[] bamboo, int[] requests) { System.out.println("bamboo: a=" + bamboo[0] + ", b=" + bamboo[1]); for (int request : requests) { System.out.print(request + " "); } System.out.println(); } }