Розіб'ємо вхідний масив на дві рівні частини: t_1, t_2, ..., t_{n/2} і t_{n/2+1}, t_{n/2+2}, ..., t_n. Першу частину збережемо в масиві , другу — в масиві .
Спочатку вирішимо задачу для послідовності . Переберемо всі її можливі підмножини (їх буде не більше 2^{20}). Для кожної підмножини обчислимо суму її елементів , і для кожної такої суми збільшимо значення на . Як структуру даних можна використовувати, наприклад, unordered_map. Таким чином, буде містити кількість способів вибрати підмножину з масиву з сумою елементів, рівною .
Потім переберемо всі підмножини масиву . Нехай — сума елементів однієї з таких підмножин. Якщо об'єднати цю підмножину з усіма підмножинами масиву , сума елементів яких дорівнює s - sum, то в результаті вийде підмножина вхідного масиву, сума елементів якої дорівнює .
Приклад
Розглянемо другий приклад. Розіб'ємо вхідну послідовність на дві частини:
a = (1, 3, 2),
b = (2 ,1, 4)
Переберемо всі підмножини множини 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]++; |
Структура після обробки буде містити наступні значення:
Тепер переберемо всі підмножини множини b = \{2, 1, 4\}. У даному прикладі шуканою сумою є s = 7. Для кожної суми , що відповідає підмножині , будемо додавати до відповіді значення m[s - sum].
\{2\}: sum = 2, m[7 - 2] = m[5] = 1;
\{1\}: sum = 1, m[7 - 1] = m[6] = 1;
\{4\}: sum = 4, m[7 - 4] = m[3] = 2;
\{2, 1\}: sum = 3, m[7 - 3] = m[4] = 1;
\{2, 4\}: sum = 6, m[7 - 6] = m[1] = 1;
\{1, 4\}: sum = 5, m[7 - 5] = m[2] = 1;
\{2, 1, 4\}: sum = 7, m[7 - 7] = m[0] = 1;
\{\}: sum = 0, m[7 - 0] = m[7] = 0;
Шукана сума дорівнює 1 + 1 + 2 + 1 + 1 + 1 + 1 + 0 = 8, що і є відповіддю.
Реалізація алгоритму
Оголосимо робочі структури даних.
vector<int> a, b;
unordered_map<long long, long long> m;Читаємо вхідні дані. Першу половину послідовності заносимо в масив , другу — в масив .
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]);Перебираємо всі підмножини послідовності і обчислюємо суми їхніх елементів. У структурі unordered_map зберігаємо, скільки разів кожна сума зустрічається серед цих підмножин. Якщо — сума поточної підмножини, то значення збільшуємо на .
for (i = 0; i < (1 << a.size()); i++)
{
sum = 0;Змінна містить бітову маску поточної підмножини . Сума її елементів обчислюється у змінній .
for (j = 0; j < a.size(); j++)
if (i & (1 << j)) sum += a[j];Для кожної знайденої суми sum збільшуємо значення на .
m[sum]++;
}Кількість способів отримати суму з елементів вихідного масиву підраховуємо у змінній .
res = 0;Перебираємо всі підмножини послідовності .
for (i = 0; i < (1 << b.size()); i++)
{
sum = 0;Змінна містить бітову маску поточної підмножини . Сума елементів цієї підмножини обчислюється у змінній .
for (j = 0; j < b.size(); j++)
if (i & (1 << j)) sum += b[j];Якщо об'єднати поточну підмножину множини , сума елементів якої дорівнює , з усіма підмножинами множини , сума яких дорівнює s - sum, то в результаті вийде підмножина вхідного масиву, сума елементів якої дорівнює .
if (m.count(s - sum) > 0) res += m[s - sum];
}Виводимо відповідь.
printf("%lld\n", res);