amankbps's blog

By amankbps, history, 12 months ago, In English

You are given an array of n integers. Your task is to calculate the bitwise or of each window of k elements, from left to right. In this problem the input data is large and it is created using a generator. Input The first line contains two integers n and k: the number of elements and the size of the window. The next line contains four integers x, a, b and c: the input generator parameters. The input is generated as follows:

problem link

how to solve this efficiently i got tle when i try to solve n*31

  • Vote: I like it
  • +9
  • Vote: I do not like it

| Write comment?
»
12 months ago, hide # |
 
Vote: I like it +16 Vote: I do not like it

Hint: Double Deque or Four Stacks (Double Stack trick to work as a deque).

»
12 months ago, hide # |
Rev. 2  
Vote: I like it +30 Vote: I do not like it

First of all, you need to construct the array $$$a$$$ from the provided generator.

After that, you split $$$a$$$ into several blocks of length $$$k$$$ with the length of the last one being at most $$$k$$$ (since $$$n \equiv 0$$$ $$$(mod$$$ $$$k)$$$ doesn't always hold), then compute the prefix and suffix OR of each of these blocks. For better understanding, here is an illustration for $$$n = 8, k = 3$$$ (I know I'm talented at drawing <(")).

Ultimately, the answer for a window $$$[i-k+1, i]$$$ is basically just $$$pre_i$$$ $$$|$$$ $$$suf_{i-k+1}$$$. For example, the OR sum of the window $$$[3, 5]$$$ is $$$pre_5$$$ $$$|$$$ $$$suf_3$$$ which is equal to $$$a_3$$$ $$$|$$$ $$$a_4$$$ $$$|$$$ $$$a_5$$$.

The resulting complexity is $$$O(n)$$$ for both time and memory.

  • »
    »
    12 months ago, hide # ^ |
    Rev. 3  
    Vote: I like it +9 Vote: I do not like it

    Loved the idea, first time I’ve come across this kind of trick!

    Attaching the Accepted C++ code for the above approach.

    C++ Code - AC
    C++ Code - Much Simpler than mine

    I initially tried a simpler implementation using a 2D vector to store prefix and suffix arrays for each segment, but that gave a RUNTIME ERROR due to overhead—especially when k = 1, leading to around 1e7 vectors being created. So, I optimized the space by reusing 1D vectors curSuff and nxtPref during segment iteration. Also Attaching that Code.

    C++ Code - RE
    • »
      »
      »
      5 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      There is a minor initialization bug in the smaller code where "s[n — 1] = x" is not true always, thanks for sharing the code btw!

  • »
    »
    12 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    Wow, how did you come up with this?

  • »
    »
    12 months ago, hide # ^ |
     
    Vote: I like it +1 Vote: I do not like it

    Thanks for sharing such a nice solution. Here is my C++ code :-)


    #include<bits/stdc++.h> using namespace std; int main() { int n, k; cin >> n >> k; int64_t x, a, b, c; cin >> x >> a >> b >> c; vector<int64_t> arr(n); vector<int64_t> prefix(n); vector<int64_t> suffix(n); arr[0] = x; for (int i = 1; i < n; i++) arr[i] = (a * arr[i - 1] + b) % c; prefix[0] = x; for (int i = 1; i < n; i++) { if (i % k == 0) prefix[i] = arr[i]; else prefix[i] = prefix[i - 1] | arr[i]; } suffix[n - 1] = arr[n - 1]; for (int i = n - 2; i >= 0; i--) { if (i % k == k - 1) suffix[i] = arr[i]; else suffix[i] = suffix[i + 1] | arr[i]; } int64_t ans = 0; int l = 0, r = k - 1; while (r < n) { if (r % k == k - 1) ans ^= prefix[r]; else ans ^= (prefix[r] | suffix[l]); r++, l++; } cout << ans << "\n"; }
  • »
    »
    10 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    amazing solution bro

  • »
    »
    10 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    The same concept is used in another CSES Range Query problem which asks to find the maximum subarray sum in a given range [l...r]. When merging two childs one of the best segment (segment with the maximum subarray sum) could lie partially in the left child and right child and it is always possible to make that segment with some suffix of left child and prefix of right child ! So we store prefix, suffix sum max of each segment (and also another stuff the ans) in each child and get the answer by quering...Same concept used here!

    • »
      »
      »
      7 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      We can say that main logic comes from the observation that range of size k cannot lie in more than 2 different k size segments.

      Functions like min, max, OR, AND follows Idempotent and associative property therefore they are Overlapping-friendly Operation.

      This trick can also be seen as the specialization of sparse table for fixed range.

  • »
    »
    7 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    Appreciated man! way too clean and way too brilliant solution!!

  • »
    »
    6 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    Literally too orz

    I drew this while implementing, just posting it here for reference

  • »
    »
    4 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    Good observation

»
12 months ago, hide # |
 
Vote: I like it -19 Vote: I do not like it

Alternative solution is observe that once bit is seen it will be on for k next windows, so just track off time for each bit and reconstruct or.

»
12 months ago, hide # |
 
Vote: I like it +3 Vote: I do not like it
»
12 months ago, hide # |
 
Vote: I like it +8 Vote: I do not like it

well i did get ac with n*30 lol, probably because the constant factor was really good https://cses.fi/paste/a871c74160e6983ec5e9d5/

»
8 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Can't we store the sum of bitcounts a window in a count array and update the or of the window?

»
8 months ago, hide # |
Rev. 2  
Vote: I like it 0 Vote: I do not like it

Soution with two stacks. Easy to understand and accepted AC. The idea is to use two stacks one for storing bitwise or of first k elements and the other is to store bitwise or of the same elements in the reverse order so we get bitwise or in reverse order. C++ code Link. https://cses.fi/paste/a0140c746968381fe1ba9b/

»
3 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Total overkill: I solved it with a segment tree of OR

»
3 months ago, hide # |
 
Vote: I like it -14 Vote: I do not like it

not sure if this is a foolish solution but im pretty sure you could just store the count of each bit and get n that way