#include #include #define INF 1023456789 using namespace std; int main() { long long s; int n; scanf("%lld%d", &s, &n); vector C(2 * n); // za n mincí ze vstupu přidáme jejich opačné hodnoty for (int i = 0; i < n; ++i) { scanf("%d", &C[i]); C[i + n] = -C[i]; } int cn = C[n - 1]; // největší mince vector R(2 * n, 0); // počty mincí při optimálním placení // zabezpečíme, aby s <= (c_n - 1) * c_{n - 1} int q = C[n - 2] * (cn - 1); if (s > q) { R[n - 1] = (s - q + cn - 1) / cn; s -= R[n - 1] * cn; } // optimální placení bez vracení vector P(s + 1, INF); P[0] = 0; vector tah_P(s + 1, -1); for (int i = 1; i <= s; ++i) for (int j = 0; j < n; ++j) if (C[j] <= i && P[i] > P[i - C[j]] + 1) { P[i] = P[i - C[j]] + 1; tah_P[i] = j; } // Q inicializujeme hodnotami z P ... vector Q(2 * cn, INF); vector tah_Q(2 * cn, -1); int t = s - 2 * cn + 1; // sumy v Q mají indexy posunuty o t int w = INF; for (int i = max(0ll, s - cn + 1); i <= s; ++i) { Q[i - t] = P[i]; w = min(w, P[i]); } // ... a dále zlepšujeme, tentokrát i s vracením for (int i = w; i != Q[s - t]; ++i) for (int j = 0; j < 2 * cn; ++j) if (Q[j] == i) // z prvků množiny M_i vytváříme prvky M_{i+1} for (int k = 0; k < 2 * n; ++k) if (0 <= j + C[k] && j + C[k] < 2 * cn && Q[j + C[k]] > i + 1) { Q[j + C[k]] = i + 1; tah_Q[j + C[k]] = k; } // zrekonstruujeme optimální placení while (tah_Q[s - t] != -1) { ++R[tah_Q[s - t]]; s -= C[tah_Q[s - t]]; } while (tah_P[s] != -1) { ++R[tah_P[s]]; s -= C[tah_P[s]]; } for (int i = 0; i < 2 * n; ++i) printf("%lld%c", R[i], (i % n == n - 1) ? '\n' : ' '); return 0; }