Meet in the middle#11431

Meet in the middle (Editorial)

Divide the input array into two equal parts: t_1, t_2, ..., t_{n/2} and t_{n/2+1}, t_{n/2+2}, ..., t_n. Store the first part in array and the second in array .

First, solve the problem for sequence . Iterate over all possible subsets of (there will be at most 2^{20} of them). For each subset, calculate the sum of its elements , and increment the value by . As the data structure , we can use, for example, an unordered_map. Thus, will contain the number of ways to choose a subset from array whose elements sum to .

Then, iterate over all subsets of array . Let be the sum of elements in one such subset. If we combine this subset with all subsets of array whose sum is equal to s - sum, the result will be a subset of the original array whose elements sum to .

Example

Let's consider the second example. Divide the input sequence into two parts:

Iterate over all subsets of the set a = \{1, 3, 2\}:

\{1\}: sum = 1, m[1]++;

\{1, 2\}: sum = 3, m[3]++;

\{3\}: sum = 3, m[3]++;

\{3, 2\}: sum = 5, m[5]++;

\{2\}: sum = 2, m[2]++;

\{1, 3, 2\}: sum = 6, m[6]++;

\{1, 3\}: sum = 4, m[4]++;

\{\}: sum = 0, m[0]++;

The structure will contain the following values after processing:

Now, iterate over all subsets of the set b = \{2, 1, 4\}. In this example, the target sum is s = 7. For each sum corresponding to a subset of , add m[s - sum] to the final answer.

The target sum is 1 + 1 + 2 + 1 + 1 + 1 + 1 + 0 = 8, which is the final answer.

Algorithm implementation

Declare the data structures.

vector<int> a, b;
unordered_map<long long, long long> m;

Read the input data. Store the first half of the sequence in array , and the second half in array .

scanf("%d %d", &n, &s);
a.resize(n / 2);
for (i = 0; i < n / 2; i++)
  scanf("%d", &a[i]);

b.resize(n - n / 2);
for (i = n / 2; i < n; i++)
  scanf("%d", &b[i - n / 2]);

Iterate over all subsets of sequence and compute the sum of their elements. In the unordered_map structure, keep track of how many times each sum occurs among these subsets. If is the sum of the current subset, then increment by .

for (i = 0; i < (1 << a.size()); i++)
{
  sum = 0;

The variable contains the bitmask of the current subset of . The sum of its elements is computed in the variable .

      for (j = 0; j < a.size(); j++)
        if (i & (1 << j)) sum += a[j];

For each obtained sum , increment the value of by .

  m[sum]++;
}

The number of ways to obtain the sum from the elements of the original array is counted in the variable .

res = 0;

Iterate over all subsets of sequence .

for (i = 0; i < (1 << b.size()); i++)
{
  sum = 0;

The variable contains the bitmask of the current subset of . The sum of the elements in this subset is computed in the variable .

  for (j = 0; j < b.size(); j++)
    if (i & (1 << j)) sum += b[j];

If we combine the current subset of set , whose sum of elements is , with all subsets of set a whose sum is s - sum, the result will be a subset of the original array whose sum of elements is equal to .

  if (m.count(s - sum) > 0) res += m[s - sum];
}

Print the answer.

printf("%lld\n", res);