Problem:
ダーツ

問題

あなたは以下のルールでダーツゲームをすることになった.

あなたは,矢を的(まと)に向かって 4 本まで投げることができる.必ずしも 4 本全てを投げる必要はなく,1 本も投げなくてもかまわない.的は N 個の部分に区切られていて,各々の部分に点数 P1,..., PN が書か れている.矢が刺さった場所の点数の合計 S があなたの得点の基礎となる.S があらかじめ決められたある点数 M 以下の場合は S がそのままあなたの得点となる.しかし,S が M を超えた場合はあなたの得点は 0 点となる.

的に書かれている点数と M の値が与えられたとき,あなたが得ることのできる点数の最大値を求めるプログラムを作成せよ.

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

1 行目には,整数 N (1 ≤ N ≤ 1000) と M (1 ≤ M ≤ 200000000 = 2 × 108)がこの順に空白区切りで書かれている.2 行目以降の第 1 + i 行目 (1 ≤ i ≤ N ) には, Pi (1 ≤ Pi ≤ 100000000 = 108 ) が書かれている.

採点用データのうち, 配点の 20% 分は N ≤ 100 を満たし,配点の 50% 分はN ≤ 300 を満たす.

N, M がともに 0 のとき入力の終了を示す. データセットの数は 10 を超えない．

出力

データセットごとにあなたが得ることのできる点数の最大値を１行に出力する.

入出力例

入力例

4 50
3
14
15
9
3 21
16
11
2
0 0

出力例

48
20

1つ目の例では,15 点の部分に 3 本,3 点の部分に 1 本の矢が刺さった場合にあなたの得点は最大になり,その得点は 48 点である.

2つ目の例では,16 点の場所に 1 本,2 点の場所に 2 本の矢が刺さった場合にあなたの得点は最大になり,その得点は 20 点である.

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in Python3 (judge verdict: Accepted)

def input_score(N):
    score = []  # 的の配点をいれる配列、投げないときの点も入れておく
    score.append(0)
    for i in range(N):
        score.append(int(input()))
    return score


def cal_four_sum_score(two_score, M):
    left = 0
    right = len(two_score) - 1
    max_score = 0
    while left != right:
        now_score = two_score[left] + two_score[right]
        if now_score < M:
            # scoreの和がMより小さい時、解の候補である
            max_score = max(max_score, now_score)
            left += 1
        elif now_score > M:
            # scoreの和がMより大きい時、解の候補ではない
            right -= 1
        else:
            # scoreの和がちょうどMになるとき、解である
            max_score = M
            break

    return max_score


def cal_two_sum_score(score):
    two_score = []  # 二回投げた時に取りうる範囲を入れる配列
    contain_sum = {}  # 二回投げたときにその値はすでに存在するか判断する配列
    for i in range(len(score)):
        for j in range(len(score)):
            now_score = score[i] + score[j]
            if not contain_sum.get(now_score):
                contain_sum[now_score] = True
                two_score.append(now_score)

    two_score.sort()  # 尺取り法を用いるためsortしておく
    return two_score


def main():
    while True:
        N, M = map(int, input().split())
        if N == 0 and M == 0:
            break
        score = input_score(N)  # 的の配点の入力
        two_score = cal_two_sum_score(score)  # 二回投げた時に取りうる点の範囲を計算
        max_score = cal_four_sum_score(two_score, M)  # 四回投げたときに取りうる点の範囲を計算
        print(max_score)


if __name__ == "__main__":
    main()