Как эффективно найти количество цифр в диапазоне, в котором цифры в номере суммируются с определенным числом - PullRequest
0 голосов
/ 05 апреля 2019

Мне дают a, b и c.a - b - это диапазон, а c - это желаемое число; требуемый вывод - это число чисел в диапазоне, которые имеют цифры, которые складываются в c.Вот условия: (1 ≤ A ≤ B <1015, 1 ≤ C ≤ 135) мой текущий код использует </p>

while (num != 0){
            sum = sum + num % 10;
            num = num / 10;
        }

, но он слишком медленный, чтобы получить полный правильный ответ;

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    long long int a, b, c;
    long long int sum = 0;
    long long int num;
    long long int finalone;
    long long int counter = 0;
    string arr[b];
    cin >> a >> b >> c;
    for (long long int x=a; x<b; x++){
        num = x;
        while (num != 0){
            sum = sum + num % 10;
            num = num / 10;
        }
        if (sum == c && counter == 0){
            finalone = x;
        }
        if (sum == c){
            counter++;
        }
        sum = 0;
    }
    cout << counter << endl;
    cout << finalone;

}

Ответы [ 2 ]

0 голосов
/ 06 апреля 2019

Прежде всего, обратите внимание, что ваше постановление проблемы немного подозрительно. Если вы рассматриваете числа до 1015, то наибольшая сумма цифр, которую вы можете получить, составляет от 999 и составляет 27. Следовательно, мы уже знаем, сколько чисел имеют сумму 27 < c <= 135;).

Далее ваш алгоритм выполняет довольно ненужные вычисления. Для каждого числа в диапазоне вы используете модуль для пересчета каждой отдельной цифры, когда в большинстве случаев меняется только одна цифра. Ваш код мог бы быть улучшен, если бы вы хранили цифры в массиве, увеличивали число «вручную» и складывали элементы массива. Хотя это не улучшит комплексность.

Попробуйте взглянуть на проблему с другой точки зрения. В основном вам нужно найти комбинации из четырех цифр, такие, что w+x+y+z = c и «объединение» этих цифр попадает в диапазон [a,b]. Например, когда c==4, тогда существует только несколько комбинаций:

1111, 211, 121, 112, 31, 22, 13

Если у вас есть эти числа, подсчитать, сколько из них попадает в данный диапазон, просто.

В шутку я решил посмотреть, можно ли реализовать стратегию перебора для вычисления во время компиляции. Мы можем вычислить сумму цифр следующим образом:

template <int x> 
using number = std::integral_constant<int,x>;

template <int x>
struct sum_of_digits : number< sum_of_digits<x/10>::value + (x%10)> {};

template <> 
struct sum_of_digits<0> : number<0> {};

Я использую помощника, чтобы проверить, равны ли два целых числа

template <int x,int y>
struct equals : std::false_type {};

template <int x>
struct equals<x,x> : std::true_type {};

Соединяя их вместе, мы можем проверить, имеет ли число заданную сумму цифр:

template <int x,int c>
struct is_sum_of_digits : equals<c,sum_of_digits<x>::value> {};

Теперь мы считаем числа с правильной суммой цифр в [0,a]:

template <int a,int c> 
struct count : number<is_sum_of_digits<a,c>::value + count<a-1,c>::value> {};

template <int c> 
struct count<0,c> : number<0> {};

Для примера я использую только трехзначные числа. Пределом является рекурсия шаблона из std::index_sequence, который я использую. Возможно, вам придется развернуть ваш -ftemplate-depth, чтобы он скомпилировался для большего количества цифр, и мне пришлось развернуть одно из измерений, чтобы не превысить мой предел компиляторов. С результатами времени компиляции я заполняю таблицу поиска, чтобы получить результаты во время выполнения:

const int max_b = 100; // max sum of digits is 18 for 99
template <std::size_t ... is>
int get_number_of_correct_sum_impl(int a,int b,int c,std::index_sequence<is...>){

    static constexpr int table[] = { count<is,0>::value...,
         count<is,1>::value... , count<is,2>::value... ,
         count<is,3>::value... , count<is,4>::value... ,
         count<is,5>::value... , count<is,6>::value...,
         count<is,7>::value... , count<is,8>::value... ,
         count<is,9>::value... , count<is,10>::value... ,
         count<is,11>::value... , count<is,12>::value... ,
         count<is,13>::value... , count<is,14>::value... ,
         count<is,15>::value... , count<is,16>::value... ,
         count<is,17>::value... , count<is,18>::value...                                                                   
    };
    auto index = [max_b = max_b](int a,int c){ return c*max_b + a; };
    return table[index(b,c)] - table[index(a,c)];
}

int get_number_of_correct_sum(int a,int b,int c){
    return get_number_of_correct_sum_impl(a,b,c,std::make_index_sequence<max_b>{});
}

Тогда

int main() {
    for (int i=1;i<33;++i){
        std::cout << i << " " << get_number_of_correct_sum(0,i,5) << "\n";
    }
}

Печать:

1 0
2 0
3 0
4 0
5 1
6 1
7 1
8 1
9 1
10 1
11 1
12 1
13 1
14 2
15 2
...etc...

Обратите внимание, что это все еще просто грубая сила, проверяющая все числа и подсчитывающая, сколько из них выполняет условие, но это делается во время компиляции. Все, что остается во время выполнения, - это просмотреть две записи в таблице поиска и определить их разницу, т.е. O(1).

Live Demo

PS: Кредиты за помощь по справочной таблице идут на https://stackoverflow.com/a/55543931/4117728 и https://stackoverflow.com/a/55543946/4117728

0 голосов
/ 05 апреля 2019

Принимая во внимание, что

  1. Если c > 9 + 9 + 9 = 27, counter = 0.
  2. counter(a, b) = counter(1, b) - counter(1, a).

Мы можем заключить, что у вас естьтолько 1014*27 = 27378 возможные входы.Это означает, что вы можете заранее рассчитать каждое из 27378 значений, сохранить их в массиве и сократить функцию до проверки диапазона аргументов, 2 поисков в таблице и 1 вычитания.Это должно быть самое быстрое решение:)

...