Предварительная обработка: сделать вспомогательный массив, содержащий кумулятивное число нулей до заданной позиции (с aux [0] = 0)
0 1 0 0 1 1 0 //string
0 1 1 2 3 3 3 4 //aux array A[]
Для данного L..R
сканирования диапазона для единиц, для каждого индекса k 1
получить число нулей в диапазоне - операция O (1)
P[k] = (A[k] - A[L-1]) * (A[R] - A[k])
S = Sum(P[k], k=L..R)
Таким образом, у нас есть O(R-L)
время на запрос и наихудший случай O(Q*N)
для Q запросов
Но посмотрите внимательно на формулу:
P[k] = (A[k] - A[L-1]) * (A[R] - A[k]) =
A[k] * (A[R] + A[L-1]) - A[k]^2 - A[R] * A[L-1] =
A[k] * LRSum - A[k]^2 - LRProd
S = Sum(A[k] for ones) * LRSum - Sum(A[k]^2) - LRProd * NumOfOnes
Обратите внимание, что LRSum
и LRProd
являются константами для данного запроса, и мы должны вычислить суммы A [k] для позиций единиц и сумму квадратов для тех же позиций. Кажется, мы можем использовать ту же идею кумулятивного массива и получить результат в O(1)
за запрос.
Быстрая проверка дает (3+3)*5 - (9+9) - 4*2 = 30-18-8 = 4
для вашего примера.
Использование совокупных массивов:
0 1 0 0 1 1 0 //string
0 1 1 2 3 3 3 4 //aux array A[]
0 0 1 1 1 4 7 7 //aux array B[]
0 0 1 1 1 10 19 19 //aux array C[]
Result = (B[R] - B[L-1]) * (A[R] + A[L-1]) - (C[R] - C[L-1]) -
A[R] * A[L-1] * (R - L - 1 - (A[R] - A[L-1])) =
(7-1) * (4 + 1) - (19 - 1) - 4 * 1 * (7 - 2 - 4 + 1) = 4