Codeforces. Задача о размене монет. Жадный алгоритм
Решаю задачу на Codeforces. Не понимаю, почему программа не проходит 12-й тест. Это обычный жадный алгоритм. Подскажите пожалуйста, в чём ошибка.
Вот условие:
В государстве R есть n + 1 видов монет, самая дешевая из которых имеет номинал 1, а каждая следующая имеет номинал в a_i раз больше предыдущей. Требуется выплатить сумму s наименьшим числом монет. Разумеется, можно использовать несколько монет одного номинала.
Входные данные
В первой строке записаны два целых числа через пробел: n и s (1 ≤ n ≤ 10^5, 0 ≤ s ≤ 10^9) - количество типов монет, если не считать самую дешевую, и сумма, которую требуется выплатить.
Во второй строке записаны n целых чисел через пробел: a_i (2 ≤ a_i ≤ 10^9) — количество раз, в которое номинал очередной монеты больше номинала предыдущей.
Выходные данные
Выведите единственное целое число — минимальное количество монет, необходимое, чтобы выплатить сумму s.
Может дело во второй строке? А я ставлю ограничение своим coinNumber, когда его вводим. Вроде как именно он определяет количество чисел для второй строки.
входные данные
3 42
3 2 2
выходные данные
4
входные данные
5 228
5 2 5 2 5
выходные данные
8
#include <iostream>
#include <vector>
using namespace std;
int main()
{
long long coinNumber; long long sumToPay;
cin >> coinNumber >> sumToPay;
vector <long long> money{}; money.resize(coinNumber + 1);
money[0] = 1;
for (long long i(1); i <= coinNumber; ++i) // The first element is already filled
{
cin >> money[i];
money[i] *= money[i - 1];
}
long long needCoin(0);
for (long long i(coinNumber); i >= 0; --i)
{
needCoin += sumToPay / money[i];
sumToPay %= money[i];
}
cout << needCoin;
return 0;
}
Ответы (1 шт):
Проблема в переполнении. Рассмотрим такие входные данные:
7 1 3 5 17 257 641 65537 6700417
Ответ должен быть единица. Ваша программа выдаёт -1 потому что произведение номиналов равно 2^64 - 1. В массиве money последнее значение равно -1 типа long long на 64-битном компьютере.
Исправить ошибку можно изменив порядок размена на обратный. Ваша программа подбирает наибольший номинал, а можно начать с младших. Например:
5 228 5 2 5 2 5
Сколько монет младшего номинала (копеек) нужно что составить сумму 228? Любая сумма без копеек кратна пяти. Тогда копеек нужно будет 228 % 5. Когда копейки учтены, сумму можно поделить на пять и перейти к следующему номиналу:
sum factor coins next sum 228 5 228 % 5 = 3 228 / 5 = 45 45 2 45 % 2 = 1 45 / 2 = 22 22 5 22 % 5 = 2 22 / 5 = 4 4 2 4 % 2 = 0 4 / 2 = 2 2 5 2 % 5 = 2 2 / 5 = 0
Процесс аналогичен переводу числа в систему счисления с переменным основанием. Например, если все множители равны десяти, то вычислится сумма цифр в десятичной записи числа. Особенность нашего случая в том что шкала номиналов может кончится до того как сумма обнулится. В этом случае оставшуюся сумму надо прибавить к общему числу монет.
#include <iostream>
int main() {
int n_nominals;
int sum;
std::cin >> n_nominals >> sum;
int n_coins = 0;
for (int i = 0; i < n_nominals; ++i) {
int factor;
std::cin >> factor;
n_coins += sum % factor;
sum /= factor;
}
n_coins += sum;
std::cout << n_coins;
}