Форум программистов, компьютерный форум, киберфорум
Алгоритмы
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.64/25: Рейтинг темы: голосов - 25, средняя оценка - 4.64
0 / 0 / 0
Регистрация: 27.11.2014
Сообщений: 38
1

Найти минимальное число, факториал которого будет делиться на определенное число

16.09.2016, 12:44. Показов 4680. Ответов 25
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
здравствуйте,есть задача, в ходе которой нужно найти минимальное число m, факториал которого будет делится на определенное число к.
т.е. если k = 6, m = 3; k = 10; m = 5;
работа идет с числами от 810 000 000 до 820 000 000, нужна сумма всех чисел m для чисел этого промежутка.
какой самый оптимальный вариант решения этой задачи?
написал когда, но он слишком долго работает.
Кликните здесь для просмотра всего текста
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
 
           ulong sum1 = 0;
            for (int u = 840000000; u <= 850000000; u++)
            {
 
                    
                sum1 += (ulong)func1(prost(u));
            }
private int func1(List<int> x)
        {
            x.Sort();
            int k = 1;
            int l = 0;
            int fact = 0;
            foreach(int xi in x)
            {
                if (k != xi)
                {
                    
                    int fact1=0;
                    int i = 0;
                    while(l>0)
                    {
                        fact1 += k;
                        i++;
                        if (i % k == 0)
                            l -= (i / k + 1);
                        else
                            l -= 1;
 
                    }
                    fact = fact < fact1 ? fact1 : fact;
                    k = xi;
                    l = 1;
                }
 
                else
                {
                    l++;
                }
            }
            int fact2 = 0;
            int ii = 0;
            while (l > 0)
            {
                fact2 += k;
                ii++;
                if (ii % k == 0)
                    l -= (ii / k + 1);
                else
                    l -= 1;
 
            }
            fact = fact < fact2 ? fact2 : fact;
            return fact;
        }
        private List<int> prost(int x)
        {
            List<int> prostlist = new List<int>();
            if (x == 1)
            {
                prostlist.Add(1);
                return prostlist;
            }
            for (int i = 2; i <= x; i++)
                if (x % i == 0)
                {
                    prostlist.Add(i);
                    x /= i;
                    List<int> newprost = prost(x);
                    foreach (int y in newprost)
                        prostlist.Add(y);
                    break;
                }
            while (prostlist.Contains(1))
                prostlist.Remove(1);
            return prostlist;
 
        }
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
16.09.2016, 12:44
Ответы с готовыми решениями:

Найти натуральное наименьшее число n, факториал которого превышает число 4000
Написать программу для решения следующей задачи,используя,по крайней мере, два вида циклов. Найти...

Найти минимальное число, ктоторое больше 400 и нацело делиться на 16
Пустяковая задача жду вашей руки спасения Напишите программу поиска минимального числа, ктоторое...

Найти минимальное число большее введенного n, которые нацело делиться на 19. (while, repeat)
2...Найти минимальное число большее введенного n, которые нацело делиться на 19. (while, repeat)

Найти такое число в двоичной записи которого содержится минимальное число нулей
Среди простых чисел, не превосходящих заданного N, найти такое, в двоичной записи которого...

25
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,470
20.09.2016, 17:53 21
Лучший ответ Сообщение было отмечено sapbufer как решение

Решение

Author24 — интернет-сервис помощи студентам
У меня получается 14144.

Вот простой вариант:
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
long Solve(long maxn, int maxpow)
{
    var bit = new BitArray((int)maxn);
    var set = new HashSet<int>();
    long count = 0;
    for (long n = 2; n < maxn; n++)
    {
        if (bit[(int)n])
            continue;
        set.Clear();
        long p = 1;
        for (int k = 1; ; k++)
        {
            p *= n;
            if (p >= maxn)
                break;
            bit[(int)p] = true;
            for (int pow = 3; pow < maxpow; pow++)
            {
                var pk = pow * k;
                if (p != 2 && !set.Contains(pk))
                    set.Add(pk);
            }
        }
        count += set.Count;
    }
    return count;
}
Вместе с числом сразу обрабатываем все его степени. Обработанные числа "отмечаем" в битовом массиве.
Цикл начинаем с 2, чтобы обработать все степени двойки.

Его можно оптимизировать:
1. Начинать цикл в строке 12 с k = 2, а для k = 1 сразу добавлять count += maxpow - 3;
2. После этого цикл в строке 12 становится ненужным для n > sqrt(maxn)

Вот оптимизированный вариант:
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
long OptimizedSolve(long maxn, int maxpow)
{
    var sqrt = (long)Math.Ceiling(Math.Sqrt(maxn));
    if (sqrt < 3)
        sqrt = 3;
    var bit = new BitArray((int)maxn);
    var set = new HashSet<int>();
    long count = 0;
    for (long n = 2; n < sqrt; n++)
    {
        if (bit[(int)n])
            continue;
        set.Clear();
        if (n > 2)
            count += maxpow - 3;
        var p = n;
        for (int k = 2; ; k++)
        {
            p *= n;
            if (p >= maxn)
                break;
            bit[(int)p] = true;
            for (int pow = 3; pow < maxpow; pow++)
            {
                var pk = pow * k;
                if ((n == 2 || pk >= maxpow) && !set.Contains(pk))
                    set.Add(pk);
            }
        }
        count += set.Count;
    }
    for (long n = sqrt; n < maxn; n++)
    {
        if (bit[(int)n])
            continue;
        count += maxpow - 3;
    }
    return count;
}
1
0 / 0 / 0
Регистрация: 27.11.2014
Сообщений: 38
20.09.2016, 17:57  [ТС] 22
Shamil1, у меня в первом варианте также получилось, хотел себя перепроверить, решив по-другому,видимо в алгоритме проблемы. Спасибо!
0
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,470
21.09.2016, 11:44 23
Цитата Сообщение от sapbufer Посмотреть сообщение
хотел себя перепроверить, решив по-другому
Обычно в таких случаях сначала пишут наиболее простое решение ("в лоб"). Например:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
long Test(long maxn, int maxpow)
{
    var set = new HashSet<long>();
    for (int n = 3; n < maxn; n++)
        for (int p = 3; p < maxpow; p++)
        {
            double pow = Math.Pow(n, p);
            if (pow > long.MaxValue) throw new OverflowException($"ERROR {pow}!!!");
            long np = (long)pow;
            if(!set.Contains(np))
                set.Add(np);
        }
    return set.Count;
}
А затем используют его для проверки своего оптимизированного решения на небольших входных данных (на больших обычно "решение в лоб" не работает из-за проблем с производительностью и т.п.).
1
90 / 87 / 11
Регистрация: 20.11.2008
Сообщений: 724
21.09.2016, 16:20 24
Цитата Сообщение от Shamil1 Посмотреть сообщение
Алгоритм вычисления k в GetK() меня немного смущает... но всё равно всё время уходит на разложение на множители
А я всё-таки попробовал подумать над GetK, но на скорости вычислений действительно не отражается
вот мой вариант
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
        static int GetK(int p, int cnt)
        {
            List<int> pwrs = new List<int>();   //здесь степени p
            List<int> pwrsSum = new List<int>();    //здесь суммы степеней
 
            int s = 1;
            int pw = 1;
            while (s <= cnt)
            {
                pwrs.Add(pw);
                pwrsSum.Add(s);
                pw *= p;
                s += pw;
            }
 
            int k = 0;
            for(int i = pwrs.Count - 1; i >= 0; i--)
            {
                s = pwrsSum[i];
                int cntOld = cnt;
                cnt = cnt % s;
                k += (cntOld - cnt) / s * pwrs[i];
            }
            return k * p;
        }
2
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,470
21.09.2016, 18:08 25
C#
1
2
3
4
5
6
7
            for(int i = pwrs.Count - 1; i >= 0; i--)
            {
                s = pwrsSum[i];
                int cntOld = cnt;
                cnt = cnt % s;
                k += (cntOld - cnt) / s * pwrs[i];
            }
Можно обойтись одним делением.
C#
1
2
3
4
5
6
7
    for (int i = pwrs.Count - 1; i >= 0; i--)
    {
        s = pwrsSum[i];
        int d = cnt / s;
        k += d * pwrs[i];
        cnt -= d*s;
    }
Добавлено через 22 минуты
И можно не использовать списки:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static int GetK(int p, int cnt)
{
    int bn = 1;
    while (bn < cnt)
    {
        bn *= p;
    }
 
    int k = 0;
    while (bn >= 1)
    {
        int sn = (bn * p - 1) / (p - 1);
        int d = cnt / sn;
        k += d * bn;
        cnt -= d * sn;
        bn = bn / p;
    }
    
    return k * p;
}
(подставил формулу для суммы геометрической прогрессии)
(не тестировал)
1
90 / 87 / 11
Регистрация: 20.11.2008
Сообщений: 724
21.09.2016, 19:11 26
Цитата Сообщение от Shamil1 Посмотреть сообщение
Можно обойтись одним делением.
точно
Цитата Сообщение от Shamil1 Посмотреть сообщение
И можно не использовать списки
хорошая идея. Только операций больше получается
0
21.09.2016, 19:11
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
21.09.2016, 19:11
Помогаю со студенческими работами здесь

Найти такое число в двоичной записи которого содержится минимальное число нулей
Среди простых чисел, не превосходящих заданного N, найти такое, в двоичной записи которого...

Найти вероятность того, что наугад взятое 5-значное число будет делиться на 39
Мы решили эту задачу через программу, но не знаем как решить её на бумаге. Ответ получился 2.5%

Минимальное число которое делиться на 17
Напечатать минимальное число, большее 200, которое нацело делится на 17.

Факториал. Определить максимальное число, факториал которого хранится в переменной типа int
/*Доброго времени суток ! Задача такова: Пользователь вводит число с клавы. Вывести на экран...


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

Или воспользуйтесь поиском по форуму:
26
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru