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 C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <vector>

#define REP(i, n) for (int i = 0; i < n; i++)
#define FOR(i, m, n) for (int i = m; i < n; i++)
#define ALL(a) (a).begin(), (a).end()
#define CEIL_DIV(a, b) (a % b ? a / b + 1 : a / b)
#define FLOOR_DIV(a, b) (a / b)

using namespace std;

#define MAX_OF_SUM (2000 * 2000 + 100)
bitset<MAX_OF_SUM> set;

int main() {
    int N;
    cin >> N;

    set[0] = true;

    long long sum = 0;

    REP(i, N) {
        int a;
        cin >> a;
        // (これまでに到達できたもの << a) : aを足した場合に到達できるもの
        // これと，これまでに到達できるもののORを取れば，両方の組み合わせを列挙できたことになる
        set |= set << a;
        sum += a;
    }

    // 組み合わせの全列挙のうち，中央値とは，sum/2以降に最初に現れるもの
    // 理由:
    // ある部分数列には，対応する部分数列が存在する(2進表現でNOTしたもの)
    // 大きい方をP, 小さい方をSとすると，P+S = sumになる．
    // ここで，S<=Pより，S <= sum/2 <= P が全ての組み合わせについて成立
    // よってソートすると，S_s(1), S_s(2), ..., sum/2, P_p(1), P_p(2) ... sum が成立．
    // n=2だと，01 (sum/2) 10 11 なので，中央値は10，一般に中央値はP_p(1)．
    // より，sum/2以降で最初に現れる和が求める答えである．
    //
    // 2 1を考えると，sum = 3, sum/2 = 1，和は 1 (sum/2) (2) 3
    // 1 1を考えると，sum = 2, sum/2 = 1, 和は 1 (sum/2) (2) 2
    // より，sum/2はCEIL_DIVする必要がある．

    for (long long i = CEIL_DIV(sum, 2); i < MAX_OF_SUM; i++) {
        if (set[i]) {
            cout << i << endl;
            return 0;
        }
    }

    return 0;
}