Всем привет! Пытался написать свою программу, но она у меня получается очень долгая. В интернете адекватных объяснений на java не нашел. Вот задача:
Найдите все натуральные числа, принадлежащие отрезку [35 000 000; 40 000 000], у которых ровно пять различных нечётных делителей (количество чётных делителей может быть любым). В ответе перечислите найденные числа в порядке возрастания.
В ответе 4 числа
Java
Задание 25, java
Кроме варианта с делением на потоки (еще вариант - использование CUDA), я что-то ничего путного тут не вижу, 11 миллиардов действий выполнить придется все равно. Непонятен момент с тривиальным делителем 1, если он считается, то это сокращает время проверки на 20%. Непонятен момент с полным квадратом тоже - это 2 одинаковых делителя или 1? Еще моменты для ускорения:
1. Если мы нашли более 5 делителей, остальные искать уже не надо.
2. Делители искать не до полного числа, и даже не до половины, а до корня из него. Но при этом придется делить и на четные и проверять, что получается. Все равно будет быстрее, чем н/2. Пример:
50=1*50=2*25 (3 4 не подходят)=5*10 (6 7 не подходят) - 3 делителя, включая тривиальный (дальше 7 не проверяем).
Следующая программка на C# работала примерно 10 секунд (без учета 1, полные квадраты идут как 2, Core i7 4 котла):
static bool OddDivisors5(int n)
{
int Result = 0;
for (int i = 2; i <= (int)Math.Sqrt(n); i++)
{
if (n % i == 0)
Result += ((n / i) & 1) + (i & 1);
if (Result > 5)
return false;
}
return Result == 5;
}
static void Main(string[] args)
{
ConcurrentBag<int> Result = new ConcurrentBag<int>();
Parallel.For(35000000, 40000001, x => {
if (OddDivisors5(x))
Result.Add(x);
});
foreach (int i in Result)
Console.WriteLine(i);
Console.ReadLine();
}
1. Если мы нашли более 5 делителей, остальные искать уже не надо.
2. Делители искать не до полного числа, и даже не до половины, а до корня из него. Но при этом придется делить и на четные и проверять, что получается. Все равно будет быстрее, чем н/2. Пример:
50=1*50=2*25 (3 4 не подходят)=5*10 (6 7 не подходят) - 3 делителя, включая тривиальный (дальше 7 не проверяем).
Следующая программка на C# работала примерно 10 секунд (без учета 1, полные квадраты идут как 2, Core i7 4 котла):
static bool OddDivisors5(int n)
{
int Result = 0;
for (int i = 2; i <= (int)Math.Sqrt(n); i++)
{
if (n % i == 0)
Result += ((n / i) & 1) + (i & 1);
if (Result > 5)
return false;
}
return Result == 5;
}
static void Main(string[] args)
{
ConcurrentBag<int> Result = new ConcurrentBag<int>();
Parallel.For(35000000, 40000001, x => {
if (OddDivisors5(x))
Result.Add(x);
});
foreach (int i in Result)
Console.WriteLine(i);
Console.ReadLine();
}
Решение задачи можете увидеть здесь: https://pastebin.com/A0QiG1Br
*¹ «Нам необязательно перебирать все числа» Мы итерируем до корня из числа, чтобы программа смогла быстрее совершить операцию благодаря хитрости в *²
*² Если число делится на другое число, тогда оно обязательно будет делиться на результат от деления этих чисел - парные делители. Рассмотрим число 10 - оно делится на 5. 10/5 = 2 - это значит, что 10/2 = 5.
Рассмотрим число 15 - оно тоже делится на 5. 15/5 = 3 - это значит, что 15/3 = 5.
То есть из первого делителя вытекает всегда второй делитель
*¹ «Нам необязательно перебирать все числа» Мы итерируем до корня из числа, чтобы программа смогла быстрее совершить операцию благодаря хитрости в *²
*² Если число делится на другое число, тогда оно обязательно будет делиться на результат от деления этих чисел - парные делители. Рассмотрим число 10 - оно делится на 5. 10/5 = 2 - это значит, что 10/2 = 5.
Рассмотрим число 15 - оно тоже делится на 5. 15/5 = 3 - это значит, что 15/3 = 5.
То есть из первого делителя вытекает всегда второй делитель
Игорь Евгеньевич
В 11. строке уберите count
В 21. строке сделайте "public static Set<Integer> divs(int n)"
В 21. строке сделайте "public static Set<Integer> divs(int n)"
Игорь Евгеньевич
Прошлое решение вычислялось 152730ms (153 секунды, почти 3 минуты!)
Небольшой speed boost к решению (Внимание! Числа выводятся не в порядке возрастания!): https://pastebin.com/1wMgbHdp
Новое решение вычисляется за 75683ms на моём пк (или 76 секунд)
Это ровно очень прям почти-почти-почти в 2 раза меньше. Вы можете использовать еще больше потоков, если для вас это долго, к примеру, сократить диапазон с 500 до 250 тысяч, но, соответственно, и нагрузка на процессор тоже увеличится.
Небольшой speed boost к решению (Внимание! Числа выводятся не в порядке возрастания!): https://pastebin.com/1wMgbHdp
Новое решение вычисляется за 75683ms на моём пк (или 76 секунд)
Это ровно очень прям почти-почти-почти в 2 раза меньше. Вы можете использовать еще больше потоков, если для вас это долго, к примеру, сократить диапазон с 500 до 250 тысяч, но, соответственно, и нагрузка на процессор тоже увеличится.
Игорь Евгеньевич
Также советую ознакомиться с данным материалом: https://youtu.be/MCd4E3wWyaM
И вам также стоит учесть, что в 2022 году на апробации ЕГЭ по Информатике, а также на самом досрочном экзамене дали немного иное задание с маской числа
И вам также стоит учесть, что в 2022 году на апробации ЕГЭ по Информатике, а также на самом досрочном экзамене дали немного иное задание с маской числа
Похожие вопросы
- Помогите понять как решить задание по Java.
- Всем привет. Помогите плз. Мне нужна помощь тех кто действительно хорошо знает Java т. к мне нужно выбрать один из курсов
- Помогите доделать код на java. В форму пользователь вводит символ, который нужно заменить на #.
- Не выводит изображение в JAVA
- Java проблема с рефлексией.
- Java Developer vs Android Developer. Куда дальше?
- Пишут ли стартапы на Java?
- С какой книги начинать изучение Java?
- Помогите сделать java приложение! { СРОЧНО }
- Java и какой толк работать именно в консоле?
class ege1 {
public static void main(String[] args) {
int a, b, c, d;
for (a = 35000000; a < 40000001; a++) {
d = 0;
for (b=1; b<(int) Math.sqrt(a); b=b+2) {
c = a % b;
if (c == 0) d++;
if (d>6) break;
}
if (d==5) System.out.println(a);
}
}
}
Не понял. Когда его разрабатывали, хотели его даже назвать Microsoft Java, пока Sun не пообещал мелкомягким анальные кары. Но если настаиваешь - держи, еще с небольшой оптимизацией (уменьшено количество проверок на превышение количества делителей):
static bool OddDivisors5(int n)
{
int Result = 0;
for (int i = 2; i <= (int)Math.Sqrt(n); i++)
if (n % i == 0)
{
Result += ((n / i) & 1) + (i & 1);
if (Result > 5)
return false;
}
return Result == 5;
}
Последнее найденное число: