Нам потрібно визначити, які суми можна отримати, вибравши деяку підмножину монет. Кожну монету можна:
не використовувати;
використати лише один раз.
Тому це різновид задачі Knapsack.
Нехай сума всіх монет дорівнює S = x_1 + x_2 + ... + x_n. Оскільки n \le 100 та x_i \le 1000, то S \le 100000. Це дозволяє зберігати інформацію про кожну можливу суму.
Визначимо
Спочатку ми ще не використали жодної монети. Сума завжди досяжна: dp[0] = 1. Усі інші значення дорівнюють нулю. Для прискорення зберігати будемо в бітсеті.
Для кожної монети з номіналом x_i:
зсуваємо бітсет на x_i позицій;
об'єднуємо результат із вихідним бітсетом:
Підраховуємо кількість встановлених бітів, крім .
Послідовно перебираємо суми від до і виводимо ті, для яких dp[s] = 1.
Реалізація алгоритму
У бітсеті будемо зберігати масив .
#define MAX 100010
bitset<MAX> mask;Читаємо кількість монет . Встановлюємо dp[0] = 1, оскільки суму можна отримати, не використовуючи жодної монети.
scanf("%d", &n);
mask.set(0);У змінній обчислюємо суму номіналів усіх монет.
s = 0;У циклі послідовно обробляємо всі монети.
for (i = 0; i < n; i++)
{Обробляємо монету з номіналом .
scanf("%d", &w);
s += w;
mask |= (mask << w);
}Повертаємо кількість встановлених бітів. Однак сума завжди досяжна, тому її необхідно виключити.
printf("%d\n", mask.count() - 1);Виводимо всі досяжні додатні суми.
for (i = 1; i <= s; i++)
if (mask[i]) printf("%d ", i);
printf("\n");