Я думаю, что цифры должны иметь разные позиции, это красная сельдь.Вы можете использовать принцип включения-исключения, чтобы подсчитать количество всех позиций (i, j, k, l, m), где x [i] + x [j] + x [k] + x [l] + x [m] = S и i, j, k, l, m различны:
sums with i!=j,i!=k,i!=l...,l!=m = all sums
- sums with i=j
- ...
- sums with l=m
+ sums with i=j and j=k
+ ...
+ sums with k=l and l=m
- ...
+ sums with i=j=k=l=m
Вычисление сумм справа, кроме первой, выполнимо в O (N ^ 2 log N).Например, чтобы найти количество позиций (i, i, k, l, m), таких что x [i] + x [i] + x [k] + x [l] + x [m] = S, вы можетесоздать отсортированные массивы с суммами {2a + b} и {c + d} и проверить, имеют ли они элементы x, y, такие что x + y = S.
Основной алгоритм
Так что достаточно вычислить, сколько там позиций (i, j, k, l, m), где x[i]+x[j]+x[k]+x[l]+x[m]=S
и i, j, k, l, m не обязательно различаются.По сути, вы можете использовать решение Морона следующим образом:
Создать отсортированный массив сумм {a + b: a, b - числа из массива};сгруппируйте равные элементы в один, запомнив количество.Например, для массива [1,1,3] вы получите девять сумм [2,2,2,2,4,4,4,4,6] вида a + b.Затем вы группируете одни и те же элементы, помня количество: [(2,4), (4,4), (6,1)].Этот шаг O (N ^ 2 log N).
Для каждого e подсчитайте, сколько в массиве пар элементов, которые суммируются с Se.Как и в решении Морон, у вас есть два указателя, один направо, а другой налево.Если сумма слишком мала, переместите первый указатель, увеличив сумму;если сумма слишком велика, переместите второй указатель, уменьшив ее.
Предположим, что сумма верна.Это означает, что один указывает на (a, x), а второй на (b, y), где a + b = Se.Увеличьте счетчик на x * y и переместите оба указателя (Вы можете переместить только один указатель, но на следующем шаге совпадения не будет, и тогда будет перемещен второй указатель.).
Например, для массива [(2,4), (4,4), (6,1)] и Se = 8 первый указатель указывает на (2,4), а второй на (6,1)).Поскольку 2 + 6 = 8, вы добавляете 4 и перемещаете оба указателя.Теперь они оба указывают на (4,4), поэтому вы увеличиваете счетчик на 16. Не останавливайтесь!Указатели переходят друг в друга, и вы получаете сначала в (6,1), затем в (2,4), увеличиваете счетчик на 4.
Итак, в итоге, есть 4 + 16 + 4= 24 способа получить 8 как сумму из 4 элементов [1,1,3]:
>>> len([k for k in itertools.product([1,1,3],repeat=4) if sum(k) == 8])
24
Prelude Control.Monad> length [k | k <- replicateM 4 [1,1,3], sum k == 8]
24
Повторяя, что для каждого e вы получите количество способов получить S как сумму5 элементов.
Для [1,1,1,1,1] и Se = 4 массив сумм будет [(2,25)], и вы получите 625 способовполучить сумму 4.
Для каждого e этот шаг является линейным по размеру массива (так что это O (N 2 )), поэтому цикл принимает O (N 3 ).
При включении-исключении :
Назовите пятерку (i, j, k, l, m) "правильной", если x [i] + х [J] + х [к] + х [л] + х [м] = S.Цель состоит в том, чтобы посчитать количество правильных пятерок (i, j, k, l, m), где i, j, k, l, m попарно различны.Основной алгоритм может подсчитать в O (N ^ 3), сколько существует правильных пятерок, которые не обязательно имеют разные компоненты.Осталось подсчитать эти «неправильные» кортежи.
Рассмотрим подмножества правильных пятерок
A xy = {(i, j, k, l, m).): индексы на x-м и y-м месте одинаковы}
Например, A 24 - набор правильных пятерок (i, j, k, l, m)где j = l.
Набор неправильных пятерок:
A 12 ∪ A 13 ∪ ... ∪ A 45
Подсчет количества элементов по включению-исключению:
| A 12 ∪ A 13 ∪ ... ∪ A 45 |= | A 12 |+ | A 13 |+ ... + | A 45 |- | A 12 ∩ A 23 |- ... - | A 34 ∩ A 45 |+ ... + | A 12 ∩ A 23 ∩ ... ∩ A 35 ∩ A 45 |
Здесь есть 2 10 = 1024 слагаемых.Но количество кардинальных чисел одинаково.
Единственное, на что нужно рассчитывать:
- X 1 = | A 12 |- в пять раз с i = j
- X 2 = |A 12 ∩ A 23 |- в пять раз с i = j = k
- X 3 = | A 12 ∩ A 23 ∩ A 34 |- в пять раз с i = j = k = l
- X 4 = | A 12 ∩ A 23 ∩ A 34 ∩ A 45 |- в пять раз с i = j = k = l = m
- X 5 = | A 12 ∩ A 34 |- пятерок с i = j, k = l
- X 6 = | A 12 ∩ A 23 ∩ A 45 |- пятерок с i = j = k, l = m
Вы можете наблюдать, переставляя, все остальные наборы представлены здесь.Например, A 24 имеет ту же мощность, что и A 12 .
Подсчет количества элементов в этих 6 наборах довольно прост.Для первого вы создаете массивы {2a + b} и {c + d} и подсчитываете, сколько там общих элементов;для остальных есть только 3 или менее свободных переменных, поэтому даже простой цикл даст вам O (N ^ 3).
Чтобы упростить сумму, я написал следующую программу на Haskell:
import Control.Monad
import Data.List
import qualified Data.Map as Map
-- Take equivalence relation, like [(1,2),(2,3)] and return its partition, like [3,1,1]
f xs = sort $ map length $ foldr f (map return [1..5]) xs
where f (x,y) a = let [v1] = filter (x `elem`) a
[v2] = filter (y `elem`) a
in if v1 == v2 then a else (a \\ [v1,v2]) ++ [v1++v2]
-- All 1024 subsets of [(1,2),(1,3), ..., (4,5)]
subsets = filterM (const [False, True]) [(i,j) | i <- [1..5], j <- [i+1..5]]
res = Map.fromListWith (+) $ map (\k -> (f k, (-1)^(length k))) subsets
*Main> res
Loading package array-0.3.0.1 ... linking ... done.
Loading package containers-0.3.0.0 ... linking ... done.
fromList [([1,1,1,1,1],1),([1,1,1,2],-10),([1,1,3],20),([1,2,2],15),([1,4],-30),([2,3],-20),([5],24)]
, что означает, что формула имеет вид
все подмножества - 10X 1 + 20X 2 - 30X 3 + 24X 4 + 15X 5 - 20X 6 .
Проверка:
Сколько существует пятерок в [0,0,0, ..., 0] суммирование до 0?Один способ вычислить это напрямую, второй способ - использовать формулу (а не заботиться о различных позициях):
direct x = x*(x-1)*(x-2)*(x-3)*(x-4)
indirect x = x^5 - 10 * x^4 + 20 * x^3 + 15 * x^3 - 30 * x^2 - 20*x^2 + 24*x
*Main> direct 100
9034502400
*Main> indirect 100
9034502400
Другие замечания:
Также,есть решение O ( n log n ): Вычислить (x a 1 + ... + x a n ) 5 с использованием БПФ, результатом является коэффициент при x S .Это позволяет использовать i дважды, но вы можете вычесть многочлены, такие как (x 2a 1 + ... + x 2a n ) 5 * (x a 1 + ... + x a n ) 3 и т. Д. В соответствии с принципом включения-исключения.
В некоторых ограниченных моделях вычислений было показано для решения этой задачи требуется O(N ^ 3) время.