Моя проблема. Учитывая , я хочу , чтобы подсчитать число действительных мультимножествами . Мультисеть действительна, еслиS S
- Сумма элементов является , ин
- Каждое число от до может быть выражена однозначно как сумма некоторых элементов .п S
Пример. Например , если , то являются действительными.{ 1 , 1 , 1 , 1 , 1 } , { 1 , 2 , 2 } , { 1 , 1 , 3 }
Тем не менее, является недопустимым , так как 2 могут быть образованы как и (то есть, 2 может быть выражена как и и ), так что второе условие не выполнено. Аналогично 3 могут быть образованы и .{ 1 , 1 } { 2 } 2 = 1 + 1 2 = 2 { 2 , 1 } { 1 , 1 , 1 }
1 5 S 5 } также недопустимо, поскольку все числа от до могут быть выполнены однозначно, но сумма элементов не равна .
Я пытался найти хороший алгоритм для этой проблемы в течение достаточно долгого времени, но не могу решить его. Это из codechef . Я видел некоторые из представленных решений, но все еще не мог понять логику решения проблемы. ПРИМЕЧАНИЕ: ограничение по времени для вопроса составляет 10 секунд и
Для мультимножества я буду использовать обозначение , если , что означает происходит раза в мультинаборе S.a i < a j i < j a i c i
До сих пор я сделал некоторые выводы
- Первый элемент необходимого отсортированного мультимножества должен быть
- Пусть будет множеством, следующим за двумя свойствами, тогда ∀ r < k a r + 1 = a r или ( ∑ r i = 0 a i ) + 1
- Пусть , где встречается раз, следует требуемым свойствам, тогда из вышеприведенного вывода можно сказать, что и если .
Доказательство:a i c i ∀ i a i | n + 1 a i | a j j > i a i + 1 =
- Теперь рассмотрим т.е. все последующие числа после 1 будут кратны . Итак, пусть будет числом возможных таких множеств, тогда где я суммирую все возможные числа ( ). Другими словами,д е ( п ) f ( n ) = ∑ d | n + 11's=d-1f(n-1)=g(n)=∑d| n,d≠ng(d)
Наконец, моя проблема сводится к этому - найти эффективным способом, чтобы он не превышал ограничение по времени.
источник
Ответы:
Вот что делает самое быстрое решение . Это действительно вычисление вашей функции Учитывая , мы ее разлагаем (см. ниже), а затем вычислить все факторы (см. ниже) в некотором порядке, так что подразумевает (свойство P). Теперь мы вычислим по формуле, пройдя факторы в указанном порядке. Свойство P гарантирует, что когда мы вычисляем , мы уже вычислили для всех нетривиальных множителей of . Также есть оптимизация (см. Ниже).
Более подробно мы рассмотрим факторы по порядку, и для каждого фактора мы найдем все его нетривиальные факторы, проверив, какой из делит .f 1 , … , f i - 1 f ifi f1,…,fi−1 fi
Факторинг: Предварительная обработка: мы составляем список всех простых чисел ниже используя сито Эратосфена. Учитывая , мы просто используем пробное деление. н109 n
Генерация всех факторов: это делается рекурсивно. Предположим, что . Бежим Вложенные циклы , и выход , Вы можете доказать свойство P по индукции. т л 1 ∈ { 0 , ... ,n=pk11⋯pktt t р л 1 1 ⋯ р л т тl1∈{0,…,k1},…,lt∈{0,…,kt} pl11⋯pltt
Оптимизация: поскольку программа запускается на нескольких входах, мы можем использовать памятку для экономии времени на разных входах. Мы запоминаем только небольшие значения (до ), и это позволяет нам хранить все запомненные значения в массиве. Массив инициализируется нулями, и поэтому мы можем сказать, какие значения уже известны (поскольку все вычисленные значения являются положительными).105
Если первичная факторизация равна , то зависит только от и фактически только от отсортированной версии этот вектор. Каждое число ниже имеет не более простых факторов (с повторением), и, поскольку , представляется возможным вычислить (или, скорее, ) для всех из них, рекурсивно. Это решение могло бы быть быстрее, если бы было много разных входов; как есть, их максимум .p k 1 1 , … , p k t tn+1 pk11,…,pktt ( k 1 , … , k t ) 10 9 29 p ( 29 ) = 4565 f g 10f(n) (k1,…,kt) 109 29 p(29)=4565 f g 10
Также возможно, что эта функция, отображающая разбиения на соответствующие , имеет явный аналитический вид. Например, , задается A000670 , а задается A005649 или A172109 .g ( p k ) = 2 k - 1 g ( p 1 … p t ) g ( p 2 1 p 2 … p t )g g(pk)=2k−1 g(p1…pt) g(p21p2…pt)
источник
Итак, у вас есть рекуррентное отношение для (см. Конец вашего вопроса).g(⋅)
На данный момент кажется, что естественным подходом было бы записать рекурсивный алгоритм для вычисления и применить запоминание, чтобы вы не вычисляли более одного раза. Другими словами, когда вы вычисляете , вы сохраняете его в хеш-таблице, которая отображает ; если вам нужно узнать снова в будущем, вы можете посмотреть его в хеш-таблице.g ( i ) g ( i ) i ↦ g ( i ) g ( i )g(n) g(i) g(i) i↦g(i) g(i)
Это требует факторинга , но существуют эффективные алгоритмы факторинга когда .n n ≤ 10 9n n n≤109
Вы также можете посмотреть на последовательность в энциклопедии целочисленных последовательностей . Если вы найдете последовательность в их энциклопедии, иногда они будут предоставлять дополнительную полезную информацию (например, эффективные алгоритмы для вычисления последовательности). Это правда , может взять удовольствие от вещей, хотя.g(1),g(2),g(3),g(4),g(5),…
источник
Вот подсказка, чтобы вы начали. Применение стандартных алгоритмов динамического программирования для перечисления множества разбиений целого числа, и добавить некоторую логику проверку , которая из них позволяет уникальные изменениям решений путем итеративной проверки всех сумм, делая изменения и проверки уникальности.
В немного более подробно: Предположим , у вас есть мультимножество . Учитывая число с , как вы можете определить подмножество которое суммируется с ? Как вы можете проверить, является ли этот подмножество уникальным? Попробуйте адаптировать стандартные методы динамического программирования для внесения изменений . (Смотрите также этот вопрос .)S i 1≤i≤n S i
Учитывая мультимножество , как можно проверить, удовлетворяет ли оно второму условию, т. Можно ли однозначно выразить каждое число от 1 до как сумму подмножества (уникальное условие внесения изменений)? Это должно быть довольно легко, если вы решили предыдущий.S n S
пусть обозначает список мультимножеств, которые удовлетворяют обоим вашим условиям. Если вы знали , как вы могли бы использовать эту информацию для построения ? Здесь вы можете адаптировать стандартные методы динамического программирования для перечисления разделов целого числа.P(n) P(1),P(2),…,P(n) P(n+1)
Вот подход, который, вероятно, будет лучше.
Предположим, что является мультимножеством, которое удовлетворяет обоим вашим условиям (для ). Как мы можем расширить его, чтобы получить мультимножество которое имеет еще один элемент? Другими словами, как мы можем определить все способы добавить еще один элемент в , чтобы получить новый мультимножество которое удовлетворяет обоим вашим условиям (для некоторого )?S n T S T n′
Ответ: если можно выразить как сумму некоторых элементов из , то нет смысла добавлять его в : это приведет к нарушению условия уникальности. Таким образом, мы можем перечислить все целые числа которые не могут быть выражены в виде суммы некоторых элементов из ; каждый из них может быть потенциально добавлен в для получения нового мультимножества которое будет удовлетворять обоим условиям (для некоторого другого ).x S S T x S S T n
Более того, можно перечислить, какие целые числа можно выразить как сумму некоторых элементов , а какие нет, используя динамическое программирование. Вы строите двумерный массив логических значений , где имеет значение true, если есть способ выразить целое число в виде суммы некоторых из первые элементы из (только первые элементы из могут использоваться; где был отсортирован, поэтому и ). Обратите внимание, чтоS A[1…|S|,1…n] A[i,j] j i S i S S S={s1,s2,…,sk} s1≤s2≤⋯≤sk A[i,j] можно вычислять, используя значения : в частности, если , или противном случае. Это позволяет определить все числа , которые являются кандидатами для добавления в .A[1…i−1,1…j−1] A[i,j]=A[i−1,j]∨A[i−1,j−si] j>si A[i,j]=A[i−1,j] S
Далее, для каждого возможного расширения для (полученного путем добавления одного элемента к ) мы хотим проверить, удовлетворяет ли обоим условиям. Пусть обозначает сумму элементов и сумма элементов . Нам необходимо проверить , соответствует ли каждое целое число в интервале можно выразить в виде суммы некоторых из элементов . Это тоже можно решить с помощью динамического программирования, используя стандартные алгоритмы для внесения изменений. (На самом деле, если у вас еще есть массивS S T n S n ′ T n + 1 , n + 2 , … , n ′ T A A [ 1 … |T S S T n S n′ T n+1,n+2,…,n′ T A упомянутое выше, вы можете легко расширить его, чтобы решить эту проблему: мы делаем его массивом , продолжаем заполнять все дополнительные записи и проверяем, что все верны.) Итак, теперь мы можем перечислить все мультимножества которые расширяют одним элементом, который удовлетворяет обоим условиям.A[1…|T|,1…n′] T SA[|T|,n+1],A[|T|,n+2],…,A[|T|,n′] T S
Это сразу предлагает алгоритм для перечисления всех мультимножеств которые удовлетворяют вашему условию, для всех вплоть до некоторой границы, скажем, . У нас будет массив , где хранит все мультимножества , сумма которых равна 5, и, как правило, хранит набор всех мультимножеств , сумма которых равна .n n ≤ 20 P [ 1 … 20 ] P [ 5 ] S P [ n ] S nS n n≤20 P[1…20] P[5] S P[n] S n
Далее мы можем заполнить итеративно. Начните с установки чтобы он содержал только один мультимножество . Далее, для каждого (считая от 1 до 20), для каждого , перечислим все возможные расширения для (используя методы, описанные выше), пусть обозначает сумму элементов , и вставьте в если его еще нет и если .P [ 1 ] { 1 } n S ∈ P [ n ] T S n ′ T T P [ n ′ ] n ′ ≤ 20P[n] P[1] {1} n S∈P[n] T S n′ T T P[n′] n′≤20
Это должно быть довольно выполнимо. Удачи! Повеселись! Работа с деталями будет хорошим обучающим упражнением в динамическом программировании.
источник