Разбор
Обозначим через количество способов составить сумму из первых номиналов монет. Это количество равно сумме двух величин:
количества способов составить сумму с использованием первых номиналов (то есть без использования -го номинала) и
количества способов составить сумму с использованием всех номиналов.
Таким образом, имеем соотношение:
Изначально положим при .
Пример
Рассмотрим второй пример. В этом примере сумма , а количество номиналов . Последний номинал имеет стоимость . Согласно соотношению, имеем:
Сумму можно составить, используя первые три номинала , четырьмя способами:
Сумму можно составить с использованием всех четырех номиналов одним способом:
Реализация алгоритма
Объявим рабочие массивы.
long long dp[51][251]; int a[51];
Значение будем сохранять в .
long long f(int k, int n) { if (k == 0 && n == 0) return 1; if (k == 0 || n < 0) return 0; if (dp[k][n] != -1) return dp[k][n]; return dp[k][n] = f(k - 1, n) + f(k, n - a[k]); }
Основная часть программы. Читаем входные данные.
memset(dp, -1, sizeof(dp)); scanf("%d %d", &n, &m); for (i = 1; i <= m; i++) scanf("%d", &a[i]);
Выводим искомое количество способов.
printf("%lld\n", f(m, n));
Python реализация
Значение будем сохранять в .
def f(k, n): if k == 0 and n == 0: return 1 if k == 0 or n < 0: return 0 if dp[k][n] != -1: return dp[k][n] dp[k][n] = f(k - 1, n) + f(k, n - a[k]) return dp[k][n]
Основная часть программы. Читаем входные данные.
n, m = map(int, input().split()) a = [0] + list(map(int, input().split())) dp = [[-1 for _ in range(n + 1)] for _ in range(m + 1)]
Выводим искомое количество способов.
print(f(m, n))