Java

Задание 25, java

Всем привет! Пытался написать свою программу, но она у меня получается очень долгая. В интернете адекватных объяснений на java не нашел. Вот задача:

Найдите все натуральные числа, принадлежащие отрезку [35 000 000; 40 000 000], у которых ровно пять различных нечётных делителей (количество чётных делителей может быть любым). В ответе перечислите найденные числа в порядке возрастания.

В ответе 4 числа
Кроме варианта с делением на потоки (еще вариант - использование 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();
}
Мансур Ахмедов
Мансур Ахмедов
65 389
Лучший ответ
Александр Савочкин вот, что у меня получилось на 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);
}
}
}
Мансур Ахмедов >не очень разбираюсь в c#
Не понял. Когда его разрабатывали, хотели его даже назвать 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;
}

Последнее найденное число:
Решение задачи можете увидеть здесь: https://pastebin.com/A0QiG1Br

*¹ «Нам необязательно перебирать все числа» Мы итерируем до корня из числа, чтобы программа смогла быстрее совершить операцию благодаря хитрости в *²

*² Если число делится на другое число, тогда оно обязательно будет делиться на результат от деления этих чисел - парные делители. Рассмотрим число 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)"
Игорь Евгеньевич Прошлое решение вычислялось 152730ms (153 секунды, почти 3 минуты!)

Небольшой speed boost к решению (Внимание! Числа выводятся не в порядке возрастания!): https://pastebin.com/1wMgbHdp
Новое решение вычисляется за 75683ms на моём пк (или 76 секунд)
Это ровно очень прям почти-почти-почти в 2 раза меньше. Вы можете использовать еще больше потоков, если для вас это долго, к примеру, сократить диапазон с 500 до 250 тысяч, но, соответственно, и нагрузка на процессор тоже увеличится.
Игорь Евгеньевич Также советую ознакомиться с данным материалом: https://youtu.be/MCd4E3wWyaM

И вам также стоит учесть, что в 2022 году на апробации ЕГЭ по Информатике, а также на самом досрочном экзамене дали немного иное задание с маской числа