import sys from math import gcd from bisect import bisect_right import pypyjit pypyjit.set_param( "threshold=1," "function_threshold=1," "trace_eagerness=1," "decay=0" ) # 63 bit / word # # 64 bit にすると 2^63 以上の値が現れて PyPy の多倍長整数に # 昇格する可能性がある。 W = 63 # r bit 左シフトするとき、 # 下側 word に残る部分だけを先に mask する。 # # これにより # # (x & LOW_MASK[r]) << r < 2^63 # # が常に成立する。 LOW_MASK = [0] * W r = 1 while r < W: LOW_MASK[r] = (1 << (W - r)) - 1 r += 1 def solve(): data = list(map(int, sys.stdin.buffer.read().split())) pos = 0 T = data[pos] pos += 1 out = [""] * T tc = 0 while tc < T: n = data[pos] S0 = data[pos + 1] pos += 2 end = pos + n freq = {} g = 0 total = 0 while pos < end: a = data[pos] pos += 1 if a <= S0: total += a g = gcd(g, a) freq[a] = freq.get(a, 0) + 1 if not freq: out[tc] = "0" tc += 1 continue if total <= S0: out[tc] = str(total) tc += 1 continue # 全ての部分和は g の倍数なので問題を縮約する。 S = S0 // g pairs = [] capped_sum = 0 min_a = S + 1 max_a = 0 for aa, c in freq.items(): a = aa // g # これを超える個数は、どの feasible subset にも入らない。 lim = S // a if c > lim: c = lim pairs.append((a, c)) capped_sum += a * c if a < min_a: min_a = a if a > max_a: max_a = a # 使用可能個数まで削った後、全部入る。 if capped_sum <= S: out[tc] = str(capped_sum * g) tc += 1 continue # ------------------------------------------------------------ # 値域が狭い場合の高速処理 # # k = floor(S / max_a) # # k 個なら最大値だけを k 個選んでも S 以下。 # # 一方、 # # (k + 1) * min_a > S # # なら k+1 個は絶対に選べない。 # # よって「大きい順に k 個」が最適。 # ------------------------------------------------------------ k = S // max_a if (k + 1) * min_a > S: pairs.sort(reverse=True) need = k ans = 0 i = 0 m = len(pairs) while need and i < m: a, c = pairs[i] if c < need: take = c else: take = need ans += a * take need -= take i += 1 out[tc] = str(ans * g) tc += 1 continue # ------------------------------------------------------------ # bounded subset sum # # c 個の同じ値 a を # # a, 2a, 4a, ... # # に二進分解する。 # ------------------------------------------------------------ chunks = [] for a, c in pairs: p = 1 while c: if p < c: take = p else: take = c chunks.append(a * take) c -= take p <<= 1 chunks.sort() # 二進分解後にも同じ判定を入れる。 min_c = chunks[0] max_c = chunks[-1] k = S // max_c if (k + 1) * min_c > S: out[tc] = str(sum(chunks[-k:]) * g) tc += 1 continue # ------------------------------------------------------------ # S/2 より大きい chunk は、解に高々 1 個しか入らない。 # # したがってこれらは bitset に投入しない。 # ------------------------------------------------------------ split = bisect_right(chunks, S >> 1) top_word = S // W # +2 にして carry の境界判定を削除する。 bits = [0] * (top_word + 2) bits[0] = 1 # 処理済み chunk の総和。 # reachable bit の上限として使う。 cap = 0 target_word = top_word target_bit = S - target_word * W i = 0 # ------------------------------------------------------------ # 固定長 bitset DP # ------------------------------------------------------------ while i < split: a = chunks[i] # shift 元として見る必要がある最大 bit。 # # x > S-a なら x+a > S なので無視できる。 lim = cap sa = S - a if lim > sa: lim = sa src = lim // W q = a // W r = a - q * W if r == 0: while src >= 0: x = bits[src] if x: bits[src + q] |= x src -= 1 else: low_mask = LOW_MASK[r] rr = W - r while src >= 0: x = bits[src] if x: dst = src + q # 下側 # # shift 前に mask することで # 多倍長整数への昇格を防ぐ。 bits[dst] |= (x & low_mask) << r # 上側 carry bits[dst + 1] |= x >> rr src -= 1 cap += a if cap > S: cap = S # S が作れた時点で終了。 if (bits[target_word] >> target_bit) & 1: out[tc] = str(S * g) break i += 1 else: # -------------------------------------------------------- # 各 word より前にある非零 word を記録する。 # # S/2 より大きい chunk に対する # # max reachable <= S-a # # を O(1) 近くで求めるため。 # -------------------------------------------------------- prev = [-1] * (top_word + 1) last = -1 j = 0 while j <= top_word: if bits[j]: last = j prev[j] = last j += 1 # small chunks のみで作れる最大値。 wi = top_word rb = S - wi * W x = bits[wi] if rb != W - 1: x &= (1 << (rb + 1)) - 1 if x: best = wi * W + x.bit_length() - 1 else: wi -= 1 if wi >= 0: wi = prev[wi] if wi >= 0: best = wi * W + bits[wi].bit_length() - 1 else: best = 0 # -------------------------------------------------------- # 大きい chunk を 1 個だけ加える。 # -------------------------------------------------------- i = split m = len(chunks) while i < m: a = chunks[i] limit = S - a wi = limit // W rb = limit - wi * W x = bits[wi] if rb != W - 1: x &= (1 << (rb + 1)) - 1 if x: small_best = wi * W + x.bit_length() - 1 else: wi -= 1 if wi >= 0: wi = prev[wi] if wi >= 0: small_best = ( wi * W + bits[wi].bit_length() - 1 ) else: small_best = 0 v = a + small_best if v > best: best = v if best == S: break i += 1 out[tc] = str(best * g) tc += 1 sys.stdout.write("\n".join(out)) if __name__ == "__main__": solve()