Go: ///
// File:  0529.go
// Author: ymiyamoto
//
// Created on Wed Feb 28 20:39:28 2018
//
package main

import (
	"fmt"
	"sort"
)

func max(n, m int64) int64 {
	if n < m {
		return m
	} else {
		return n
	}
}

func main() {
	for {
		var N int
		var M int64
		fmt.Scan(&N, &M)
		if N == 0 && M == 0 {
			break
		}

		arr := make([]int64, N+1)
		for i := 1; i <= N; i++ {
			fmt.Scan(&arr[i])
		}
		sort.Slice(arr, func(i, j int) bool { return arr[i] < arr[j] })

		sums := make([]int64, len(arr)*len(arr))
		for i := 0; i < len(arr); i++ {
			for j := 0; j < len(arr); j++ {
				sums[i*len(arr)+j] = arr[i] + arr[j]
			}
		}

		sort.Slice(sums, func(i, j int) bool { return sums[i] < sums[j] })

		var m int64 = 0
		for i := 0; i < len(sums); i++ {
			rem := M - sums[i]
			if rem >= 0 {
				index := sort.Search(len(sums), func(i int) bool { return sums[i] > rem }) - 1
				if index >= 0 {
					m = max(m, sums[i]+sums[index])
				}
			}
		}
		fmt.Println(m)
	}
}

C++: #include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <fstream>
using namespace std;

int solve(int*, int, int);
int main(){
  int n, points;
  while(cin>>n>>points, n!=0 && points!=0){
    int darts[n+1]; //投げない場合を考えるため、1つだけ多く取っておく
    darts[0]=0; //投げない場合
    for(int i=1; i<=n; i++) cin >> darts[i];


    //ダーツを2回投げた時の場合を考える
    //ループを抜けた後に cnt=(n+1)*(n+1)
    int cnt=0;
    int set[(n+1)*(n+1)];
    for(int i=0; i<=n; i++){
      for(int j=0; j<=n; j++){
        set[cnt++]=darts[i]+darts[j];
      }
    }

    //upper_boundを使うためソート
    sort(set, set+(n+1)*(n+1));

    int ans=0;
    for(int i=0; i<(n+1)*(n+1); i++){
      int aim = points-set[i];//目標
      if(aim<0) continue;
      int last = *(upper_bound(set, set+(n+1)*(n+1), aim)-1);
      if(set[i]+aim <= points) ans=max(ans, set[i]+last);
    }


    printf("%d\n", solve(darts, n+1, points));
  }

  return 0;
}

/*
int solve(int* darts, int size, int point){
  int temp[size*size];
  int k=0;
  //2本投げ終わった後の合計点数を探索
  for(int i=0; i<size; i++){
    for(int j=0; j<size; j++){
      temp[k++]= darts[i]+darts[j];
    }
  }

  sort(temp, temp+size*size);

  int ans=0;
  for(int i=0; i<size*size; i++){
    int aim = point-temp[i];
    if(aim<0) continue;
    int last = *(upper_bound(temp, temp+size*size, aim)-1);
    if(temp[i]+last<=point) ans=max(ans, temp[i]+last);
  }

  return ans;
}
*/


int solve(int* darts, int size, int points){
  //ダーツを2回投げた時の場合を考える
  //ループを抜けた後に cnt=(n+1)*(n+1)
  int cnt=0;
  int set[size*size];
  for(int i=0; i<size; i++){
    for(int j=0; j<size; j++){
      set[cnt++]=darts[i]+darts[j];
    }
  }

  //upper_boundを使うためソート
  sort(set, set+size*size);

  int ans=0;
  for(int i=0; i<size*size; i++){
    int aim = points-set[i];//目標
    if(aim<0) continue;
    int last = *(upper_bound(set, set+size*size, aim)-1);
    if(set[i]+aim <= points) ans = max(ans, set[i]+last);
  }
  return ans;
}

C++: #include <iostream>
#include <sstream>
#include <vector>
#include <list>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <algorithm>
#include <numeric>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
using namespace std;

typedef long long INT;
typedef vector <INT> VI;
typedef set <INT> SI;

INT solve( VI Q, INT M ) {
    INT answer = 0;
    int n = Q.size();
    for ( int i = 0; i < n; ++ i ) {
        int q = Q[i];
        int L = 0;
        int R = n;
        INT m = M - q;
        while ( L < R ) {
            int p = ( R - L ) / 2 + L;
            INT t = q + Q[p];
            if ( t > M ) t = 0;
            answer = max( answer, t );
            if ( Q[p] >= m ) {
                R = p;
            } else {
                L = p + 1;
            }
        }
    }
    return answer;
}

int main() {
    int n, m;
    while ( cin >> n >> m ) {
        if ( n == 0 && m == 0 ) break;
        VI P( n );
        for ( int i = 0; i < n; ++ i ) {
            cin >> P[i];
        }
        SI Q_;
        Q_.insert( 0 );
        for ( int i = 0; i < n; ++ i ) {
            Q_.insert( P[i] > m ? 0 : P[i] );
            for ( int j = 0; j < n; ++ j ) {
                Q_.insert( ( P[i] + P[j] > m ? 0 : P[i] + P[j] ) );
            }
        }
        VI Q( Q_.begin(), Q_.end() );
        cout << solve( Q, m ) << endl;
    }
    return 0;
}

C++: #include<bits/stdc++.h>
using namespace std;

#define rep(i, n) for (int i=0; i<n; i++)
typedef long long int ll;

int N, M;
ll P[1111];
ll PP[1111];
int p;

int main(int argc, char *argv[])
{
  while(cin >> N >> M, N){
    int NN = N * N;
    rep(i, N) cin >> P[i];
    rep(i, N) rep(j, N) PP[i + j * N] = P[i] + P[j];
    sort(P,  P  + N );
    sort(PP, PP + NN);
    ll res = 0;
    res = max(res,  P[upper_bound(P,  P  + N,  M) -  P - 1]);
    res = max(res, PP[upper_bound(PP, PP + NN, M) - PP - 1]);    
    rep(i, N) res = max(res, PP[upper_bound(PP, PP + NN, M -  P[i]) - PP - 1] +  P[i]);
    rep(i, NN) if((p = upper_bound(PP, PP + NN, M - PP[i]) - PP - 1) >= 0) res = max(res, PP[p] + PP[i]);
    rep(i, NN) if((p = upper_bound(PP, PP + NN, M - PP[i]) - PP - 1) >= 0) res = max(res, PP[p] + PP[i]);
    cout << res << endl;
  }
  
  
  return 0;
}

C++: #include<iostream>
#include<iomanip>
#include<algorithm>
#include<array>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<numeric>
#include<set>
#include<stack>
#include<string>
#include<sstream>
#include<unordered_map>
#include<queue>
#include<vector>
using namespace std;

#define int long long
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;

#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define rrep(i,a,b) for(int i=(b)-1;i>=(a);i--)
#define all(a) (a).begin(),(a).end()
#define dump(o) if(DEBUG){cerr<<#o<<" "<<o<<endl;}
#define dumpc(o) if(DEBUG){cerr<<#o; for(auto &e:(o))cerr<<" "<<e;cerr<<endl;}
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
const int MOD = 1e9 + 7;
const bool DEBUG = false;

signed main() {
	int P[1010] = {};
	static int a[1000010] = {};
	for (int N, M; cin >> N >> M&&N;) {
		rep(i, 0, N)cin >> P[i];
		P[N] = 0;
		N++;
		rep(i, 0, N)rep(j, 0, N) {
			a[i*N + j] = P[i] + P[j];
		}
		sort(a, a + N*N);

		int ans = 0;
		rep(i, 0, N*N) {
			if (a[i] > M)break;
			int add = a[upper_bound(a, a + N*N, M - a[i]) - a - 1];
			ans = max(ans, a[i] + add);
		}
		cout << ans << endl;
	}
	return 0;
}

C++: #include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

#define INF 100000000
int sum[1000*1000];
int v[1000];
int n, m;

int main(){
    int n, m;
    while(cin >> n >> m, n||m){
        
        for(int i=0; i<n; ++i){
            int a; cin >> a;
            v[i] = a;
        }
        sort(v, v + n);
        
        int maxV=0;
        
        for(int i=0; i<n; ++i){
            for(int j=0; j<n; ++j){
                sum[i*n+j] = v[i]+v[j];
                //cout << sum[i*n+j] << end;
            }
        }
        sort(sum, sum+n*n);
        for(int i=0; i<n; ++i){
            for(int j=0; j<n; ++j){
                for(int i=0; i<=m-v[i]-v[j]; i++){
                    int t = sum[upper_bound(sum,sum + n*n, m-v[i]-v[j])-sum-1];
                    if(v[i]+v[j]+t<=m) {
                        maxV=max(maxV,v[i]+v[j]+t);
                    }
                }
            }
        }
        cout << maxV << endl;
    }
}