Форум программистов, компьютерный форум, киберфорум
Алгоритмы
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.73/30: Рейтинг темы: голосов - 30, средняя оценка - 4.73
Эксперт функциональных языков программированияЭксперт по математике/физике
4315 / 2106 / 432
Регистрация: 19.07.2009
Сообщений: 3,220
Записей в блоге: 24

Число, делящееся на n и с суммой цифр n

04.12.2013, 15:21. Показов 6632. Ответов 47
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Встала задача, которую нужно решить в кратчайшие сроки, но решения я не могу придумать.

Дано число n (от 1 до 1000), необходимо найти такое минимальное m, что m=kn и ds(m)=n, где ds возвращает сумму цифр числа в 10-й системе записи. Работаем в натуральных числах.
Ограничения по времени: несколько секунд.

Варианты решения.
Кликните здесь для просмотра всего текста
Составляем потенциально бесконечную (т.е. делается цикл) последовательность [n,2n,3n,...], ищем в ней первое вхождение числа m, для которого ds(m)=n.

Оптимизация: составляем ряд (а по факту цикл) не с n, а с f*n, т.е. [f*n,(f+1)*n,...], где f выбирается из соображения, например, что f*n не меньше e(n), где e(n) — минимальное число, для которого ds(e(n))=n.
e(n) состоит из: e mod 9 — первая цифра, далее (n div 9) девяток.
Кликните здесь для просмотра всего текста
Составляем потенциально бесконечную последовательность чисел, для которых ds=n, причём отсортированных в порядке возрастания. Первый элемент — e(n).
Далее ищем первое вхождение числа, которое делится на n.

Оптимизация: поскольку речь идёт о длинных числах, то можно подготовить последовательность mods=[1 mod n, 10 mod n, 100 mod n, 1000 mod n, ...] и сохранить в памяти, тогда m mod n по модулю n будет совпадать со свёрткой m как последовательности цифр [m0,m1,m2,...] и mods, т.к.
https://www.cyberforum.ru/cgi-bin/latex.cgi?m=\sum_{k=0}^p m_k 10^k \equiv \sum_{k=0}^p m_k \rm{mods}_k \; (\rm{mod}\;n)

Основная проблема: слишком затратно по времени.
Например, очень тяжелыми оказываются n=101 и n=202, про случаи, когда n кратно 5, 25 или по-другому не взаимопростое со степенью десятки, вообще можно отдельно говорить.

Например, второй метод не срабатывает, если n mod 9=1, а истинное решение имеет на одну цифру больше e(n). Тогда истинное решение стоит на позиции ~p^9, где p — число цифр e(n), а это где-то 20-50.

Помогите пожалуйста, я вообще иссяк в идеях, а нужно очень срочно.
1
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
04.12.2013, 15:21
Ответы с готовыми решениями:

Число с наибольшей суммой цифр
Ребят, такая проблема. Нужно решить задачу вида: задано число, найти целое положительное число, не превосходящее заданное, с максимальной...

Из 8 различных цифр составить число, делящееся на любую из этих цифр
Необходимо из 8 различных цифр составить число, делящееся на любую из этих цифр. Добавлено через 9 минут Не понимаю как сделать цикл...

Дано трёхзначное число. Верно ли, что, удалив одну из его цифр, можно получить число, делящееся на3?
Дано трёхзначное число. Верно ли, что, удалив одну из его цифр, можно получить число, делящееся на3?

47
835 / 643 / 101
Регистрация: 20.08.2013
Сообщений: 2,524
19.12.2013, 18:05
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Igor3D Посмотреть сообщение
Покончив с девяткой мы не берем 8
Не понял. Во-первых, не понял, как мы в принципе получаем другие цифры в числе (которые не 9). А во-вторых, почему подход с набиванием максимума девяток даст минимальное число? Почему не может возникнуть ситуация, когда получится что-то типа 11999...999 вместо 3899...999?
0
1978 / 834 / 115
Регистрация: 01.10.2012
Сообщений: 5,171
Записей в блоге: 2
19.12.2013, 20:36
Цитата Сообщение от Qwertiy Посмотреть сообщение
Не понял. Во-первых, не понял, как мы в принципе получаем другие цифры в числе (которые не 9). А во-вторых, почему подход с набиванием максимума девяток даст минимальное число? Почему не может возникнуть ситуация, когда получится что-то типа 11999...999 вместо 3899...999?
Вот мы "докатились" до последней девятки x999, т.е. уже не можем впихнуть след 9 вместо х. Грубо пытаемся подобрать нужную цифру. Берем 2 (пусть это нужная сумма цифр минус текущая). Последовательно проверяем 29, 38, 47, 56, 65, 74, 83, 92. Если получили нулевой остаток, то все - найдено.

Не вышло, тогда "спускаемся вниз". На данный момент есть какая-то макс сумма цифр, уменьшаем ее на 1 и "линкуем" с девяткой и восьмеркой. Ведь возможно напр решение 7949 или 8939 или 9839 - конечно если такие пути есть. Не нашли - опять уменьшаем сумму, теперь уже последовательно перебирая 9, 8, 7. Важно что мы лупим не всю таблицу, а лишь те строки которые в сумме с цифрой дают нужную сумму

Добавлено через 35 минут
Цитата Сообщение от Igor3D Посмотреть сообщение
Грубо пытаемся подобрать нужную цифру. Берем 2 (пусть это нужная сумма цифр минус текущая). Последовательно проверяем 29, 38, 47, 56, 65, 74, 83, 92. Если получили нулевой остаток, то все - найдено.
Это не нужно (да и неправильно) - проверяем только 29, потом "спускаемся вниз"
0
835 / 643 / 101
Регистрация: 20.08.2013
Сообщений: 2,524
20.12.2013, 14:07
Igor3D, что-то я всё равно не понял идею.

Заодно, как оно соотносится с вот такими примерами?
908: 39989999999999999999999999999999999999999999 9999999899999999999999999999999999999999999999999999 999988
924: 3998979999999999999999999999999999999999999999 999999999999999999999999999999999999999999999999999 9999996
987: 89999999989999999999999999999999999999999999999999 9999999999999999989999999999999999999999999999999999999999 99
1
1978 / 834 / 115
Регистрация: 01.10.2012
Сообщений: 5,171
Записей в блоге: 2
20.12.2013, 14:42
Цитата Сообщение от Qwertiy Посмотреть сообщение
Igor3D, что-то я всё равно не понял идею.
Заодно, как оно соотносится с вот такими примерами?
Как делается сейчас: пытаемся "сконнектить" цифру со ВСЕМИ существующими путями, получая какие-то новые пути. Как хотелось бы: зная какие пути приоритетны наращивать только их, оставляя (пока) основную массу путей без внимания. Это соответствует пробегу по неск строкам в таблице (а не по всей). При этом таблица должна оставаться корректной (хранить только мин пути).

Однако же мы вышли за рамки любительской поделки Поэтому я пас.
0
835 / 643 / 101
Регистрация: 20.08.2013
Сообщений: 2,524
20.12.2013, 14:57
Т. е. речь идёт об оптимизации порядка заполнения таблицы с целью более раннего получения результата в среднем случае?
0
1978 / 834 / 115
Регистрация: 01.10.2012
Сообщений: 5,171
Записей в блоге: 2
20.12.2013, 15:02
Цитата Сообщение от Qwertiy Посмотреть сообщение
Т. е. речь идёт об оптимизации порядка заполнения таблицы с целью более раннего получения результата в среднем случае?
Да.
0
1978 / 834 / 115
Регистрация: 01.10.2012
Сообщений: 5,171
Записей в блоге: 2
21.12.2013, 07:03
Ага, есть простенькая оптимизация которая повышает скорость в 3-4 раза (в среднем). Если строка таблицы полностью заполнена, то добавлять к ней нечего, эффект нулевой. Это легко отследить добавив счетчики эл-тов для строк. Когда проходим таблицу, то цифра + текущая строка = целевая строка. Если она полностью заполнена - пропускаем. Теперь время расчета всех 1000 значений - менее 4 минут
Вложения
Тип файла: zip test_ML3.cpp.zip (1.8 Кб, 4 просмотров)
2
Модератор
Эксперт функциональных языков программирования
3141 / 2289 / 469
Регистрация: 26.03.2015
Сообщений: 8,912
11.03.2017, 21:25
Цитата Сообщение от Igor3D Посмотреть сообщение
test_ML3.cpp.zip (1.8 Кб, 4 просмотров)
Для удобства выкладываю код из файла:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <cassert>
 
int N, minRow, maxRow;
const int maxN = 1000;
const int maxNum = (maxN / 9) + 4;
 
struct Cell {
    Cell( void ) : len(0) {}
    std::string Print( void ) const;
    
// data 
    short digit;
    short len;
    short sum;
    short rem;
    const Cell * parent;
};
 
std::vector <std::vector <Cell> > tbl;
std::vector <int> rowFill;      
 
std::string Cell::Print( void ) const
{
    std::string result;
    assert(len);
    const Cell * cell = this;
    while (cell) {
        result += '0' + cell->digit;
        const Cell * nxt = cell->parent; 
        if (!nxt) break;
        for (int i = nxt->len; i < cell->len - 1; ++i)
            result += '0';
        cell = nxt; 
    }
    return result;
}
 
Cell * Check( int digit, int rem, int len, const Cell & parent )
{
    int row = digit + parent.sum;
    if (row > N) return 0;  // sum exceeds limit
    
    rem = (rem + parent.rem) % N;
    Cell & dst = tbl[row][rem];
    if (dst.len) return 0;
    
    dst.digit = digit;
    dst.len = len;
    dst.sum = row;
    dst.rem = rem;
    dst.parent = &parent;
    
    if (rem == 0 && row == N) 
        return &dst;
 
// adjust maxRow
    if (row < N && row > maxRow)
        maxRow = row;
        
// adjust minRow
    if (++rowFill[row] >= N) {
//      printf("row %d is full\n", row);
        if (row == minRow)
            for (; minRow < N; ++minRow)
                if (rowFill[row] < N) break;
    }           
        
    return 0;
}
 
Cell * DoCalc( void )
{
// alloc row fill counts
    rowFill.clear();
    rowFill.resize(N + 1);
    
// alloc table
    tbl.resize(N + 1);
    for (size_t i = 0; i < tbl.size(); ++i) {
        tbl[i].clear();     // cleanup prev data
        tbl[i].resize(N);
    }
 
// add first 10 cells
    for (int i = 0; i < 10; ++i) {
        Cell & dst = tbl[i][i % N];
        dst.digit = dst.sum = i;
        dst.len = 1;
        dst.rem = i % N;
        dst.parent = 0;
        if (i == N) return &dst;
        ++rowFill[i];
    }
    
// main loop    
    minRow = maxRow = 1;
    int prvRem = 10 % N;
    for (int num = 1; num < maxNum; ++num) {
        int endRow = maxRow;
        for (int digit = 1; digit < 10; ++digit) {
            int rem = (prvRem * (digit % N)) % N;
            int begRow = minRow - 9;
            if (begRow < 0) begRow = 0;
            int endRow = maxRow;
            for (int row = begRow; row <= endRow; ++row) {
 
                // skip the row if it's full
                if (rowFill[digit + row] >= N) continue;
                
                for (int col = 0; col < N; ++col) {
                    Cell & parent = tbl[row][col];
                    if (!parent.len) continue;
                    if (parent.len > num) continue;
                    Cell * cell = Check(digit, rem, num + 1, parent);
                    if (cell) return cell;
                }
            }       
        }   
        prvRem = (prvRem * 10) % N;  // adjust remainder
    }
    
    return 0;
}
 
int main( void )
{
    time_t begT, endT;
    time(&begT);
 
    for (N = 1; N <= maxN; ++N) {
        Cell * cell = DoCalc();
        printf("[%d] %s\n", N, cell ? cell->Print().c_str() : "not found"); 
 
#if PRINT_FILL      
        size_t tbl_size = (N + 1) * N;
        printf("size = %d (%d), %d%%\n", vec.size(), tbl_size, vec.size() * 100 / tbl_size);
#endif      
    }   
 
    time(&endT);
    int second = difftime(endT, begT);
    printf("calc time = %d:%02d\n", second / 60, second % 60);
    
    return 0;
}
Небольшие замечания по коду:

строка 9
maxNum не нужен совсем. Видимо, артефакт тестовых, нестабильных версий

строка 20
parent не нужен. Вы используете его только для восстановления ответа, а это можно сделать и без него.

строки 18-19
sum и rem тоже не нужны. Это индексы ячейки в массиве.

строка 47
Взятие остатка можно заменить на проверку с вычитанием.

строки 68-69
Смысла этого кода я не понял. Но это и не важно, так как этот код ни разу не выполняется. minRow всегда равно 1. Оптимизации нет. Вероятно, можно оптимизировать minRow точно так же, как maxRow.

строка 100
maxRow нужно начинать с 9, а не 1. Иначе теряются некоторые решения. Например, для 12 вместо 48 выдаёт 84.

строка 103
Не нужна, так как перебивается строкой 108.

строка 105
Вместо (digit % N) можно использовать просто digit.

строка 112
Выход за границы массива. Нужно ещё digit + row <= N проверять.


з.ы. После описанных исправлений у меня для всех чисел от 1 до 1000 считается примерно в 20 раз быстрее.

Добавлено через 3 минуты
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
void Main()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
 
    const int maxN = 1000;
    for (int N = 1; N <= maxN; ++N)
    {
        Console.WriteLine($"{N}: {DoCalc(N)}");
    }
 
    sw.Stop();
    Console.WriteLine($"{sw.ElapsedMilliseconds}");
}
 
 
struct Cell
{
    public short digit;
    public short len;
};
 
string DoCalc(int N)
{
    if(N < 10)
        return N.ToString();
    
    // alloc table and row fill counts
    int[] rowFill = new int[N + 1];
    Cell[,] tbl = new Cell[N + 1, N];
    // add first 10 cells
    for (int i = 0; i < 10; ++i)
    {
        tbl[i, i] = new Cell { digit = (short)i, len = 1 };
        ++rowFill[i];
    }
 
    int[] rems = new int[N];
    rems[0] = 1;
 
 
    // main loop    
    int minRow = 1, maxRow = 9;
    for (short len = 2; ; ++len)
    {
        rems[len-1] = 10 * rems[len-2] % N;
        for (short digit = 1; digit < 10; ++digit)
        {
            int rem = (rems[len-1] * digit) % N;
            int begRow = minRow > 9 ? minRow - 9 : 0;
            int endRow = minRow = maxRow;
            for (int row = begRow; row <= endRow; ++row)
            {
                // skip the row if it's full
                if (digit + row > N || rowFill[digit + row] >= N) continue;
 
                for (int col = 0; col < N; ++col)
                {
                    int prvLen = tbl[row,col].len;
                    if (prvLen == 0 || prvLen >= len) continue;
                    
                    int dstSum = digit + row;
                    if (dstSum > N) continue;
 
                    int dstRem = rem + col;
                    if (dstRem >= N) dstRem -= N;
 
                    if (tbl[dstSum, dstRem].len > 0) continue;
 
                    tbl[dstSum, dstRem] = new Cell { digit = digit, len = len };
 
                    if (dstRem == 0 && dstSum == N)
                        return Restore(dstSum, dstRem, tbl, N, rems);
 
                    ++rowFill[dstSum];
 
                    // adjust maxRow
                    if (dstSum < N && dstSum > maxRow)
                        maxRow = dstSum;
 
                    // adjust minRow
                    if (dstSum < minRow)
                        minRow = dstSum;
                }
            }
        }
    }
}
 
string Restore(int sum, int rem, Cell[,] tbl, int N, int[] rems)
{
    string result = "";
    Cell cell = tbl[sum, rem];
    while (true)
    {
        result += (char)('0' + cell.digit);
        if (cell.len < 2) break;
        sum -= cell.digit;
        rem -= cell.digit * rems[cell.len - 1] % N;
        if (rem < 0) rem += N;
        Cell nxt = tbl[sum, rem];
        for (int i = nxt.len; i < cell.len - 1; ++i)
            result += '0';
        cell = nxt;
    }
    return result;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
11.03.2017, 21:25

Массив: Определить, имеется ли в массиве хотя бы одно число, делящееся на 7 и не делящееся на 4
Дан линейный массив A, содержащий целые числа. Определить, имеется ли в массиве хотя бы одно число, делящееся на 7 и не делящееся на 4 и...

Верно ли, что, удалив одну из его цифр, можно получить число, делящееся на 3?
Дано трёхзначное число. Верно ли, что, удалив одну из его цифр, можно получить число, делящееся на 3?

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

Найти разность между суммой цифр на четных и суммой цифр на нечетных местах
Нужен код для выведения разности между суммой цифр на четных и суммой цифр на нечетных местах. Условия задачи ниже. &quot;Для делимости...

Дано натуральное число n. Найти и вывести все числа в интервале от 1 до n − 1, у которых сумма всех цифр совпадает с суммой цифр данного числа.
Дано натуральное число n. Найти и вывести все числа в интервале от 1 до n − 1, у которых сумма всех цифр совпадает с суммой цифр данного...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
48
Ответ Создать тему
Новые блоги и статьи
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru