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

import (
	"fmt"
	"sort"
)

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

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

		arr := make([]int, N+1)
		for i := 1; i <= N; i++ {
			fmt.Scan(&arr[i])
		}
		sort.Ints(arr)

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

		m := 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 <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;
    }
}

C++: import java.util.Arrays;
import java.util.Scanner;


public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		
		while(true){
			int n = sc.nextInt();
			int m = sc.nextInt();
			
			if(n == 0 && m == 0){
				break;
			}
			int[] input = new int[n];
			
			for(int i = 0; i < n ; i++){
				input[i] = sc.nextInt();
			}
			
			System.out.println(solve(input, m));
		}
	}
	
	//半分全列挙で解きたい
	static long solve(int[] array, int limit){
		int n = array.length + 1;
		int[] copyArray = new int[n];
		//0を追加した配列を作る
		for(int i = 0 ; i < n - 1; i++){
			copyArray[i] = array[i];
		}
		
		//2回投げたときに有り得る得点
		long[] twoTimes = new long[n*n];
		
		int index = 0;
		for(int i = 0; i < n; i++){
			for(int j = 0; j < n; j++){
				twoTimes[index++] = copyArray[i] + copyArray[j];
			}
		}
		
		Arrays.sort(twoTimes);
		//debug
//		for(int i = 0; i < twoTimes.length; i++){
//			System.out.println(twoTimes[i]);
//		}
		
		long result = 0;
		
		for(int i = 0; i < twoTimes.length ; i++){
			//そもそも2回だけで済む場合
			if(twoTimes[i] == limit){
				System.out.println("JUST");
				return twoTimes[i];
			}
			
			//既にオーバーしている場合も論外
			else if (twoTimes[i] > limit){
//				System.out.println("OVER i = "+i+" "+twoTimes[i]);
				break;
			}
			
			//わざと少し下を狙う
			int tmpIndex = Arrays.binarySearch(twoTimes, limit - twoTimes[i] - 1);
			
			if(tmpIndex < 0){
				tmpIndex++;
				tmpIndex *= -1;
				tmpIndex--;
			}
			
			if(tmpIndex >= twoTimes.length){
				tmpIndex = twoTimes.length - 1;
			}
			
			
			for(int j = Math.max(tmpIndex, 0); j < twoTimes.length; j++){
//				if(twoTimes[i] + twoTimes[j] > limit){
//					break;
//				}
//				System.out.println("j = "+j+" "+twoTimes[i] + " "+twoTimes[j]);
				if(twoTimes[i] + twoTimes[j] > limit){
					break;
				}
				result = Math.max(result, twoTimes[i] + twoTimes[j]);
			}
		}
		return result;
	}

}