Problem:
Score : 700 points

Problem Statement

You are given N integers A_1, A_2, ..., A_N.

Consider the sums of all non-empty subsequences of A. There are 2^N - 1 such sums, an odd number.

Let the list of these sums in non-decreasing order be S_1, S_2, ..., S_{2^N - 1}.

Find the median of this list, S_{2^{N-1}}.

Constraints

1 \leq N \leq 2000

1 \leq A_i \leq 2000

All input values are integers.

Input

Input is given from Standard Input in the following format:

N
A_1 A_2 ... A_N

Output

Print the median of the sorted list of the sums of all non-empty subsequences of A.

Sample Input 1

3
1 2 1

Sample Output 1

2

In this case, S = (1, 1, 2, 2, 3, 3, 4). Its median is S_4 = 2.

Sample Input 2

1
58

Sample Output 2

58

In this case, S = (58).

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Wrong Answer)

import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public class Main {

    static MyScanner sc;
    private static PrintWriter out;
    static long M = 1000000007;

    public static void main(String[] s) throws Exception {
        StringBuilder stringBuilder = new StringBuilder();

//        stringBuilder.append("5 20 20 20 20 20");
        if (stringBuilder.length() == 0) {
            sc = new MyScanner(System.in);
        } else {
            sc = new MyScanner(new BufferedReader(new StringReader(stringBuilder.toString())));
        }

        out = new PrintWriter(new OutputStreamWriter(System.out));
        initData();
        solve();
        out.flush();
    }

    private static void initData() {


    }

    private static void solve() {
//        BitSet kt = new BitSet(150);
//        for (int i = 0; i < 100; i+=2) {
//            kt.set(i);
//        }
//        for (int i = 0; i <= 100; i++) {
//            out.println(kt.toLeft(i));
//        }

        int r = sc.nextInt();
        int[] data = sc.na(r);
        int sum = (Arrays.stream(data).sum());
        int mm = sum / 2;

        BitSet kt = new BitSet(mm + 1);
        kt.set(0);
        for (int s : data) {
            kt.or(kt.toLeft(s));
        }
        int l = mm ;
        while (!kt.is(l)) l--;
        out.println(sum - l);
    }

    private static final class BitSet {
        private final long[] vals;

        BitSet(int v) {
            vals = new long[(v + 63) / 64];
        }

        void or(BitSet l) {
            for (int i = 0; i < vals.length; i++) {
                vals[i] |= l.vals[i];
            }
        }

        boolean is(int f) {
            return (vals[f / 64] & (1L << (f % 64))) > 0;
        }

        BitSet toLeft(int n) {
            BitSet a = new BitSet(vals.length * 64);
            int s1 = n / 64;
            int s2 = n % 64;
            if (s2 == 0) {
                System.arraycopy(vals, 0, a.vals, s1, vals.length - s1);
            } else {
                for (int i = 0; i < vals.length - s1; i++) {
                    a.vals[i + s1] = vals[i] << s2;
                }
                for (int i = 0; i < vals.length - s1 - 1; i++) {
                    a.vals[i + s1 + 1] |= vals[i] >> (64 - s2);
                }
            }
            return a;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            for (int i = vals.length - 1; i >= 0; i--) {
                String s = Long.toBinaryString(vals[i]);
                for (int k = s.length(); k < 64; k++) {
                    sb.append('0');
                }
                sb.append(s);
            }
            return sb.toString();
        }

        public void set(int i) {
            vals[i / 64] |= 1L << (i % 64);
        }
    }


    static class MyScanner {
        BufferedReader br;
        StringTokenizer st;

        MyScanner(BufferedReader br) {
            this.br = br;
        }

        public MyScanner(InputStream in) {
            this(new BufferedReader(new InputStreamReader(in)));
        }

        void findToken() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        String next() {
            findToken();
            return st.nextToken();
        }

        int[] na(int n) {
            int[] k = new int[n];
            for (int i = 0; i < n; i++) {
                k[i] = sc.nextInt();
            }
            return k;
        }

        long[] nl(int n) {
            long[] k = new long[n];
            for (int i = 0; i < n; i++) {
                k[i] = sc.nextLong();
            }
            return k;
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }
    }

}