Блог пользователя akshit.lite

Автор akshit.lite, история, 8 лет назад, По-английски

I have been thinking of an algorithm which could find the Sum Of Maximum's of all contigous sub-arrays of length k of a given Array. for each k from 1 to n , seperatly. n is the length of the array. I am able to figure out an O(N^2) solution. But could not reduce the complexity further. It would be helpful if someone could tell a sub-quadratic approach.(Possibly O(n) ). This is in reference to this problem. Any help is appreciated. NOTE : the answer for each k has to be printed seperately. Thanks :)

  • Проголосовать: нравится
  • +5
  • Проголосовать: не нравится

»
8 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Auto comment: topic has been updated by akshit.lite (previous revision, new revision, compare).

»
8 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Auto comment: topic has been updated by akshit.lite (previous revision, new revision, compare).

»
8 лет назад, # |
Rev. 4   Проголосовать: нравится +1 Проголосовать: не нравится

Sorry, misunderstood the problem statement.

»
8 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Lets focus on each element of the array. For a fixed element, we wonder how many times it will be added to our total sum. Clearly, for every subarray that includes this element as the maximum, we will add it. Let our fixed element be A[x]. Then if i is the last index on the left of x such that A[i] < A[x], and j is the last index on the right of x such that A[j] < A[x], then A[x] will be added exactly (x-i+1)(j-x+1) times(you can use combinatorics to prove this). Note that if we have A[i]=A[x] or A[j]=A[x], we can count this subarray as well, but will have to subtract out some numbers at the end because we overcounted(you can use a map to store counts of each number, then do some combinatorics).

Now the only question is, how do we calculate i and j? Let's generate j first. Iterate through the array from left to right and keep track of a multiset of elements we have seen so far. When we encounter an element, let's remove all smaller elements possible from the multiset and set their j values to be this index. Then add this element to the multiset and move on. We can do a similar thing traversing the array right to left to compute the i values.

Since we iterate and use multiset for deletion, our complexity ends up being O(N log N).

»
8 лет назад, # |
  Проголосовать: нравится +1 Проголосовать: не нравится

I solved this problem using fenwick tree. If r[n] is the result, you can figure out for each number in input array which indexes of r it affects. Each number in input array will form a pattern which can be easily processed and queried by fenwick tree.

  • »
    »
    8 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    What exactly are you storing in fenwick tree and on which parameter are you processing and querying it ? Can you please elaborate ? (facing problem since I have used only segTree most of the times)

    • »
      »
      »
      8 лет назад, # ^ |
        Проголосовать: нравится +1 Проголосовать: не нравится

      Each number in the input array will add to some indexes of r[] in a certain way. You can see that from given example in the question or generate input of your own to see. There is nothing more to the problem than that. After that you can use any interval query/process data structure.

      • »
        »
        »
        »
        8 лет назад, # ^ |
        Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

        Won't the worst case complexity of your program be 0(n*n*log(n)) as you have to update the number of times the xth element a[x] be added into r[1] , r[2] , r[3] ... r[k] , where k is the maximum size of the segment where a[x] is maximum. ? It would'nt be a constant value for all k's of a paritcular a[x], right ?

        • »
          »
          »
          »
          »
          8 лет назад, # ^ |
            Проголосовать: нравится +1 Проголосовать: не нравится

          No. What you are describing is of-course of the order O(n^2*(log(n)), But the essence of finding the pattern to be added to the result (by result i don't mean any particular r[i] but the whole result array), is that you can update array r for any a[x] in log(n) time.

»
8 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

can it can be solved in nlogn by binary search by first taking cumilative sum??

»
8 лет назад, # |
  Проголосовать: нравится +7 Проголосовать: не нравится

It can be solved in O(n):

http://pastebin.com/xeUpgjTe

For each i = 1, 2, ..., n we can find maximal p < i and minimal q > i such that a[p] >= a[i], a[q] > a[i] or p = 0 or q = n+1 (on left we have >= and on right > to not count twice the same interval). Then, if we fixed i we can observe that, for intervals of length 1, 2, 3, ... min(i-p, q-i)-1 we add to result a[i]*interval_length, for intervals of length min(i-p, q-i), ..., max(i-p, q-i)-1 we add min(i-p, q-i)*a[i] and for intervals of length max(i-p, q-i), ..., q-p-1 we add (q-p-interval_length)*a[i]. We want to have O(n) complexity, so in first case (when intervals have length < min(i-p, q-i)) we can add a[i] to some variable (in my code ,,sum"), and add a[i] to tab[min(i-p, q-i)], then when we will count answer for intervals of length i we will subtract tab[i] from sum and next add to result sum*i. Similar things we can do in second and third case.