Феерическое читерство
Рассказ слышал от одного из ребят. Итак, задача: даны два числа
k<n<10^6. Вывести в выходной файл число n, равное количеству простых чилел, лежащих между k и n.
Ограничение на память стандартное - 64Мбайт, на время работы - 2 с. Причем эксперимент показывает, что пересылка в памяти 10^8 элементов массива в тот же или другой массив занимает около 1 с, т.е. алгоритм, требующий порядка
n * n^0,5 операций (т.е. 10^9) не проходит ограничение по времени.
Внезапно одна из команд сдает решение, которое выполняется малые доли секунды и на всех тестах дает правильный ответ. Жюри в недоумении и обращается к исходному тексту программы (правила предполагают, что на тестирование сдается исходный код, который компилируется на компиляторе командной строки и потом запускается на тестах). Недоразумение развеивается.
1. Что увидело жюри, открыв файл программы?
2. Какое решение имело в виду жюри?
Комменты пока скрываются.
no subject
no subject
no subject
1. В массив забиты все простые числа от 2 до 1000000. Пробегаем по массиву, пока не встретим меньшее число, начинаем увеличивать счётчик, как только встретили большее - вываливаемся из цикла. Распечатываем наш счётчик. Всё.
Как забили простые числа в массив? Ну не руками, конечно. Написали вспомогательную программу, которую не надо сдавать жюри, перенаправили стандартный вывод (или записали прямо в файл), делов-то.
2. человеческое решение :-)
no subject
no subject
no subject
2. Сходу не скажу... :(
no subject
а хотели наверное решето эратосфена хитрое.
no subject
no subject
no subject
2. No idea, will think later.
no subject
1) Массив простых чисел от 2 до миллиона
2) Начинать надо всегда с 2, независимо от k. Каждый раз мы проверяем делимость текущего числа только на все уже известные простые числа, которых порядка ln(n). Поэтому общее время работы - n*ln(n), что есть порядка 10^8, и нас устраивает.
no subject
no subject
2. Не знаю..
no subject
1. return floor(n/log(n) - k/log(k));
Точнее, надо бы брать целое число, ближайшее к x, - не помню, как это зовется.
2. Если n мало (например, < 10^5), то рисуем решето Эратосфена. Иначе чтобы успеть, k должно быть близко к n, и проверяем на простоту все числа от k до n, сравнимые с +-1 mod 6.
no subject
no subject
2. Алгоритм тот список порождающий
no subject
а жюри имело ввиду заранее вычислить список всех простых меньше тысячи и вбить в массив в тексте программы?
no subject
no subject
no subject
2. Решето Эратосфена
а в чем проблема?
или имеется в виду что-то другое?
no subject
ЗЫ. Хотя есть ещё более читерский вариант - использовать оценку Чебышева количества простых чисел, меньших заданного. :))))
n/(ln(n)-4) > p(n) > n/ln(n)
Ну, или в каноническом варианте: 1.1*n/ln(n) > p(n) > 0.92*n/ln(n)
:-)
no subject
а ребятки просто забили в программу таблицу простых чисел?
no subject
В итоге получаем:
n/3 * (sqrt(n) / (ln(n)/2)) = 2/3 * n^1.5 / ln(n), что есть 10/9 * 10^8.
no subject
no subject
no subject
no subject
жюри же, очевидно, хотело, чтобы алгоритм был частным случаем решения подобной задачи для n<k<m, где m=10^6
no subject
no subject
no subject
1. код программы -- определение массива из всех простых чисел меньше миллиона (итого 78948, исходник получается немногим больше полумега). Дальше понятно: считаем количество элементов между k и n.
2. а кто их знает? ;) Если разрешается в коде иметь массив 168 простых чисел меньше тысячи (если не разрешается, придется при исполнении генерировать массив простых чисел меньше/равно корню из n, что увеличит время на соответствующее, но несмертельное число операций). Дальше остается перебор. Если не умничать, и напрямую пропускать при переборе только четные числа, то получается максимум n / 2 * 167 целочисленных операций mod(). Самую малость меньше, учитывая, что простые числа до тысячи (или корня n) уже и так известны. Такой порядок алгоритма (<10^8) проходит ограничение по времени?
no subject
static int p[1000000] = { 0, 0, 1, 2, 2, 3, 3, 4, ... };
где p[x] - количество простых чисел не превышающих x.
После этого программа выводила p[n] - p[k] в const time.
2) Жюри ожидало увидеть проверку на "простоту" для каждого числа между k и n. В самом наивном варианте, чтобы проверить x, на простоту, нужна итерация от 2 до sqrt(x). Отсюда n * n^0.5.
no subject
((from Alex Dribin))
Кстати, это наиболее профессионально грамотное решение ;)
А вот что было в голове у жюри я не берусь угадать. Надеюсь, что не решение методами метапрограмирования имени тов. Александреску? ;)
no subject
2. Ну, наверное, как-то так:
- найти все простые числа от 2 до sqrt{n) решетом Эратосфена - max 170 штук,
- посчитать n - n/2 - n/3 - n/5 .... + n/2/3 + n/3/5 ... - n/2/3/5 ...
- посчитать то же для k и вычесть.
Первый шаг занимает ~ 500 x 10 вычеркиваний, второй и третий ~ 170 x 170 / 2 целочисленных делений и сложений - должно уместиться. Но со статическим массивом не сравнить, конечно :-).
Без попытки ответить.
Такие задачки нам академик Ершов давал в 74 году, когда я программированию учился. На БЭСМ-6 решали. Теперь квалификацию потерял.
Но если бы у меня была практическая задача, то я бы просто использовал готовый массив простых чисел, до лимона их не так много.
no subject
no subject
no subject
no subject
no subject
Разбить этот миллион на диапазоны, скажем 1000 диапазонов по 1000 или иначе (надо прикинуть по быстродействию, но это какжется нормальный вариант).
Посчитать количество простых в каждом диапазоне и вбить в код.
На хвостах (огрызках диапазонов) посчитать уже программно.
no subject
no subject
no subject