Матч
311, Просуммировать всех (SumThemAll)
Дивизион 1,
Уровень 2
Найти сумму цифр всех чисел от lowerBound
до upperBound.
Класс: SumThemAll
Метод: long long getSum(int lowerBound, int upperBound)
Ограничения:
0 £ upperBound £ 2*109, 0 £ lowerBound £ upperBound.
Вход. Два целых числа lowerBound и upperBound.
Выход. Сумма цифр всех чисел от lowerBound до upperBound.
Пример входа
lowerBound |
upperBound |
0 |
3 |
14 |
53 |
24660 |
308357171 |
Пример выхода
6
296
11379854844
РЕШЕНИЕ
динамическое
программирование
Пусть функция f(x) вычисляет сумму цифр всех чисел от 0
до x. Тогда ответом задачи будет
значение f(upperBound)
– f(lowerBound – 1).
Заведем массив dp[10][11], в
котором dp[i][j] равно сумме цифр всех j
- значных чисел, первая цифра которых равна i.
Изначально положим dp[i][0] = 0.
Ячейка dp[0][j] содержит сумму цифр
всех чисел, содержащих менее j цифр,
то есть сумму цифр всех (j – 1) -
значных чисел, начинающихся с любой цифры включая ноль:
dp[0][j] =
Любое j - значное число, первая
цифра которого равна i, образуется из
(j – 1) - значного числа
приписыванием впереди цифры i.
Поэтому сумма их цифр равна сумме цифр (j
– 1) - значных чисел плюс цифра i,
умноженная на количество j - значных
чисел с первой цифрой i (количество
последних равно 10j-1).
Получаем соотношение:
dp[i][j] = dp[0][j] + 10j-1 * i
Остается описать вычисление функции
f(x). Очевидно, что f(0) = 0. Пусть x = . Для вычисления f(x)
разобъем множество чисел от 0 до x на
два подмножества:
1. Числа от 0 до . Сюда входят все (n + 1) - значные числа, начинающиеся цифрой 0, 1, …, an – 1. Сумма их цифр равна dp[0][n + 1] + dp[1][n + 1] + … + dp[an – 1][n + 1].
2. Числа от 0 до . Цифра an в этих числах встречается ( + 1) раз. Сумма остальных цифр этого множества равна f().
Таким образом
f(x) = + an * ( + 1) + f()
Функция info(x, *len, *FirstDigit, *Rest) по входному значению x
возвращает количество знаков в числе len,
первую цифру числа FirstDigit и число
Rest, полученное зачеркиванием первой
цифры в числе x.
рекурсивное решение
Рассмотрим рекурсивную реализацию
функции f(x). Суммирование цифр чисел
от 0 до x = разобьем на две части:
1. суммирование цифр чисел от 0
до ;
2. суммирование цифр чисел от до ;
Рассмотрим первое множество
чисел. На последней позиции повторяется последовательность из чисел 0, 1, …,
9 x
/ 10 раз. Сумма цифр от 0 до 9 равна 45, поэтому сумма единиц в числах первого
множества равна x / 10 * 45. Сумма
цифр, стоящих на других местах, равна 10
* f(x / 10 – 1).
Сумма цифр в числах второго
множества состоит из суммы цифр единиц (0 + 1 + … + a0) и суммы цифр числа = x /10, умноженного на количество чисел во множестве, то есть на (a0 + 1). Положим temp = a0 = x % 10.
Пусть sum(x) – функция, вычисляющая
сумму цифр числа x. Тогда сумма цифр
всех чисел второго множества равна
(temp + 1) * sum(x /
10) +
temp * (temp + 1) / 2
ПРОГРАММА
#include <stdio.h>
long long
dp[10][11];
int digits[10];
void info(int
x,int *len,int
*FirstDigit,int *Rest)
{
int pow10 = *len = 1; *Rest = 0;
while(x > 9)
{
(*len)++;
*Rest = *Rest + (x
% 10) * pow10;
x /= 10; pow10 *=
10;
}
*FirstDigit = x;
}
long long
f(int x)
{
int i, len, FirstDigit, Rest;
long long res;
if (x <= 0) return
0;
info(x,&len,&FirstDigit,&Rest);
for(res = i = 0; i < FirstDigit; i++)
res += dp[i][len];
return res + FirstDigit * (Rest + 1) + f(Rest);
}
class SumThemAll
{
public:
long long getSum(int lowerBound, int
upperBound)
{
int i, j, k;
for (i = 0; i < 10; i++) dp[i][0] = 0;
for (k = j = 1; j < 11; j++)
{
dp[0][j] = 0;
for (i = 0; i < 10; i++) dp[0][j] += dp[i][j -
1];
for (i = 0; i < 10; i++) dp[i][j] = dp[0][j] + k *
i;
k *= 10;
}
return f(upperBound) - f(lowerBound - 1);
}
};
Рекурсивный вариант решения задачи.
#include <stdio.h>
int sum (int
x)
{
return (x <= 0) ? 0 : x % 10 + sum(x / 10);
}
long long
f(long long x)
{
if (x <= 0) return
0;
long long res = x /
10 * 45;
long long temp = x %
10;
res = res + 10 * f(x
/ 10 - 1) + (temp + 1) * sum(x / 10) +
temp * (temp +
1) / 2;
return res;
}
class SumThemAll
{
public:
long long getSum(int lowerBound, int
upperBound)
{
return f(upperBound) - f(lowerBound - 1);
}
};