<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Тимофей Ижицкий</title><author><name>Тимофей Ижицкий</name></author><id>https://teletype.in/atom/timofeyizhitskiy</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/timofeyizhitskiy?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@timofeyizhitskiy?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=timofeyizhitskiy"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/timofeyizhitskiy?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-06-08T04:14:56.466Z</updated><entry><id>timofeyizhitskiy:2XsHxDRVYrn</id><link rel="alternate" type="text/html" href="https://teletype.in/@timofeyizhitskiy/2XsHxDRVYrn?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=timofeyizhitskiy"></link><title>Решето Эратосфена </title><published>2023-11-18T13:07:55.084Z</published><updated>2023-11-18T20:08:30.261Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/bf/92/bf92227c-3266-45ec-bcb8-0d60f5f292c5.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/90/e1/90e1acf6-7760-4223-a8ce-2a54dd8c1d5f.jpeg&quot;&gt;Решето Эратосфена</summary><content type="html">
  &lt;p id=&quot;O25G&quot;&gt;Статья написана для &lt;a href=&quot;https://t.me/sbornik_olprog&quot; target=&quot;_blank&quot;&gt;Сборника Олпрогера&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;T6Wm&quot;&gt;Достаточно часто в задачах бывает полезно - уметь факторизировать числа. В большинстве таких задач как раз используется решето Эратосфена.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;knMa&quot;&gt;Вспомним несколько определений.&lt;/p&gt;
  &lt;p id=&quot;h6PT&quot;&gt;&lt;em&gt;Простое число&lt;/em&gt; - число, которое имеет ровно два различных натуральных делителя — единицу и самого себя. &lt;/p&gt;
  &lt;p id=&quot;bkiW&quot;&gt;Если число &lt;strong&gt;не&lt;/strong&gt; простое, то оно &lt;em&gt;составное&lt;/em&gt;. &lt;/p&gt;
  &lt;p id=&quot;cRwy&quot;&gt;&lt;strong&gt;Единица&lt;/strong&gt; не является ни простым, ни составным числом.&lt;/p&gt;
  &lt;p id=&quot;TT6M&quot;&gt;Давайте сначала решим задачу капельку полегче, чем исходная: для каждого числа от &lt;code&gt;1 до n&lt;/code&gt; поймем является ли оно простым или нет.&lt;/p&gt;
  &lt;p id=&quot;mbwm&quot;&gt;Список простых чисел: &lt;code&gt;2, 3, 5, 7, 11, 13, 17, ...&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;PuZ2&quot;&gt;Заметим, что если число &lt;code&gt;x&lt;/code&gt; делится на какое-либо из чисел &lt;code&gt;от 2 до x - 1&lt;/code&gt;, то оно составное, иначе простое. Сделаем какие-то замечания:&lt;/p&gt;
  &lt;ul id=&quot;oOm1&quot;&gt;
    &lt;li id=&quot;twGL&quot;&gt;Все числа, которые делятся на &lt;code&gt;2&lt;/code&gt;, кроме самой &lt;code&gt;двойки&lt;/code&gt; точно не простые: &lt;code&gt;4, 6, 8, 10, 12, ...&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;zdpA&quot;&gt;Все числа, которые делятся на &lt;code&gt;3&lt;/code&gt;, кроме самой &lt;code&gt;тройки&lt;/code&gt; точно не простые: &lt;code&gt;6, 9, 12, 15, 18, ...&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;QKnb&quot;&gt;Все числа, которые делятся на &lt;code&gt;4&lt;/code&gt;, кроме самой &lt;code&gt;четверки&lt;/code&gt; точно не простые: &lt;code&gt;8, 12, 16, 20, ...&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;TEgz&quot;&gt;Все числа, которые делятся на &lt;code&gt;5&lt;/code&gt;, кроме самой &lt;code&gt;пятерки&lt;/code&gt; точно не простые: &lt;code&gt;10, 15, 20, 25, ...&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;20rO&quot;&gt;И так далее&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;NXxF&quot;&gt;Из этого замечания вырисовывается интересный алгоритм: давайте перебирать число &lt;code&gt;x от 2 до n&lt;/code&gt;, и помечать, что числа &lt;code&gt;2x, 3x, 4x, ...&lt;/code&gt; - составные. Если мы ни разу не пометили число, то оно является простым. Это и есть решето Эратосфена.&lt;/p&gt;
  &lt;pre id=&quot;5pd7&quot; data-lang=&quot;cpp&quot;&gt;// isPrime[i] - хранит bool в зависимости от того, что i простое или нет
// Изначального IsPrime - хранит n значений true
isPrime[1] = false; // 1 - не простое число
for (int x = 2; x &amp;lt;= n; x++) {
    // перебираем x
    for (int y = 2 * x; y &amp;lt;= n; y += x) {
        // перебираем числа вида 2x, 3x, 4x
        isPrime[y] = false;
    }
}
// после этого массив isPrime хранит корректные значения&lt;/pre&gt;
  &lt;p id=&quot;A7cZ&quot;&gt;Сперва может показаться, что этот алгоритм работает долго, но это не так. Оценка временной сложности алгоритма:&lt;/p&gt;
  &lt;figure id=&quot;1762&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/68/7b/687bd145-0d51-4875-b1a2-dbe247ae63c2.png&quot; width=&quot;1372&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;yWXZ&quot;&gt;Это так, потому что сумма &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%93%D0%B0%D1%80%D0%BC%D0%BE%D0%BD%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D1%80%D1%8F%D0%B4&quot; target=&quot;_blank&quot;&gt;гармонического ряда&lt;/a&gt; сходится к O(log n).&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;Eanz&quot;&gt;Давайте сделаем небольшую оптимазацию нашего алгоритма, а именно достаточно перебирать только &lt;strong&gt;простые&lt;/strong&gt; &lt;code&gt;x&lt;/code&gt;, и для них помечать &lt;code&gt;2x, 3x, 4x, ...&lt;/code&gt; &lt;/p&gt;
  &lt;pre id=&quot;X5Ss&quot; data-lang=&quot;cpp&quot;&gt;// isPrime[i] - хранит bool в зависимости от того, что i простое или нет
// Изначального IsPrime - хранит n значений true
isPrime[1] = false; // 1 - не простое число
for (int x = 2; x &amp;lt;= n; x++) {
    // перебираем x
    if (isPrime[x]) {
        // берем только простые x
        for (int y = 2 * x; y &amp;lt;= n; y += x) {
            // перебираем числа вида 2x, 3x, 4x
            isPrime[y] = false;
        }
    }
}
// после этого массив isPrime хранит корректные значения&lt;/pre&gt;
  &lt;p id=&quot;gpZb&quot;&gt;Используя математику можно доказать, что это работает за &lt;code&gt;O(n log (logn))&lt;/code&gt;.  При желании с доказательсвом можно ознакомиться в статьях, отмеченных внизу.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;2cEi&quot;&gt;Вернемся к исходной задаче. Мне нужно &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D0%B0%D1%8F_%D1%82%D0%B5%D0%BE%D1%80%D0%B5%D0%BC%D0%B0_%D0%B0%D1%80%D0%B8%D1%84%D0%BC%D0%B5%D1%82%D0%B8%D0%BA%D0%B8&quot; target=&quot;_blank&quot;&gt;факторизовать&lt;/a&gt; все числа от &lt;code&gt;1 до n&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;29cm&quot;&gt;Пусть я для каждого числа x знаю его минимальный простой делитель. То есть для &lt;code&gt;4 - это 2&lt;/code&gt;, &lt;code&gt;21 - это 3&lt;/code&gt;, &lt;code&gt;17 - это 17&lt;/code&gt;. Единицу проигнорируем. Обозначим минимальный простой делитель &lt;code&gt;x - minPrimeDivisor[x]&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;BcuF&quot;&gt;Тогда, чтобы разложить на простые множители число &lt;code&gt;x&lt;/code&gt;, сделаем следующее: добавим в список его простых множителей &lt;code&gt;minPrimeDivisor[x]&lt;/code&gt;, и разложим число&lt;code&gt; x / minPrimeDivisor[x]&lt;/code&gt;.  Будем повторять этот процесс, пока не получим единицу. Достаточно понятно, что алгоритм корректен. Код:&lt;/p&gt;
  &lt;pre id=&quot;i9aK&quot; data-lang=&quot;cpp&quot;&gt;for (int x = 2; x &amp;lt;= n; x++) {
    // перебираем число x, которое хотим разложить
    vector&amp;lt;int&amp;gt; factors; // список простых множителей
    int current = x; // текущее значение x
    while (current != 1) {
         factors.push_back(minPrimeDivisor[current]);
         current /= minPrimeDivisor[current];
    }
    // factor - корректный список множителей
}&lt;/pre&gt;
  &lt;p id=&quot;dCyt&quot;&gt;Тогда, чтобы решить исходную задачу, нужно научиться строить массив &lt;code&gt;minPrimeDivisor&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;iR1i&quot;&gt;Заметим, что этот массив можно поддерживать с помощью решета Эратосфена. Действительно, давайте изначально заполним массив &lt;code&gt;minPrimeDivisor[i] = i&lt;/code&gt;. Теперь, когда я перебираю простое &lt;code&gt;x&lt;/code&gt; и перебираю&lt;code&gt; y = 2x, 3x, 4x, ...&lt;/code&gt;, прорелаксируем &lt;code&gt;minPrimeDivisor[y]&lt;/code&gt; с &lt;code&gt;x&lt;/code&gt;.  Достаточно понятно, что для числа я переберу все его простые делители, а значит минимум будет посчитан корректно. Код:&lt;/p&gt;
  &lt;pre id=&quot;PPRO&quot; data-lang=&quot;cpp&quot;&gt;// isPrime[i] - хранит bool в зависимости от того, что i простое или нет
// Изначального IsPrime - хранит n значений true
// minPrimeDivisor[i] - хранит минимальный простой делитель i
// Изначально minPrimeDivisor[i] = i
isPrime[1] = false; // 1 - не простое число
for (int x = 2; x &amp;lt;= n; x++) {
    // перебираем x
    if (isPrime[x]) {
        // берем только простые x
        for (int y = 2 * x; y &amp;lt;= n; y += x) {
            // перебираем числа вида 2x, 3x, 4x
            isPrime[y] = false;
            // релаксируем minPrimeDivisor[y] с x
            minPrimeDivisor[y] = min(minPrimeDivisor[y], x);
        }
    }
}
// после этого массивы isPrime, minPrimeDivisor хранят корректные значения&lt;/pre&gt;
  &lt;p id=&quot;LZaW&quot;&gt;Также можно сократить код:&lt;/p&gt;
  &lt;pre id=&quot;RKvP&quot; data-lang=&quot;cpp&quot;&gt;for (int x = 2; x &amp;lt;= n; x++) {
    if (minPrimeDivisor[x] == x) {
        for (int y = 2 * x; y &amp;lt;= n; y += x) {
            minPrimeDivisor[y] = min(minPrimeDivisor[y], x);
        }
    }
}&lt;/pre&gt;
  &lt;p id=&quot;JvAI&quot;&gt;Итого мы научились решать задачу, которую хотели за &lt;code&gt;O(nlog(logn))&lt;/code&gt;.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;p7gJ&quot;&gt;Другие статьи:&lt;/h2&gt;
  &lt;p id=&quot;kL80&quot;&gt;&lt;a href=&quot;https://e-maxx.ru/algo/eratosthenes_sieve&quot; target=&quot;_blank&quot;&gt;E-maxx&lt;/a&gt; - описание и реализация&lt;/p&gt;
  &lt;p id=&quot;HGmF&quot;&gt;&lt;a href=&quot;https://ru.algorithmica.org/cs/factorization/eratosthenes/&quot; target=&quot;_blank&quot;&gt;Алгоритмика&lt;/a&gt; - в статье также содержится оптимазация алгоритма O(n).&lt;/p&gt;

</content></entry></feed>