Блог пользователя amankbps

Автор amankbps, история, 16 месяцев назад, По-английски

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

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

»
16 месяцев назад, скрыть # |
 
Проголосовать: нравится +16 Проголосовать: не нравится

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

»
16 месяцев назад, скрыть # |
← Rev. 2  
Проголосовать: нравится +30 Проголосовать: не нравится

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.

  • »
    »
    16 месяцев назад, скрыть # ^ |
    ← Rev. 3  
    Проголосовать: нравится +9 Проголосовать: не нравится

    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
  • »
    »
    16 месяцев назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    Wow, how did you come up with this?

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

    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"; }
  • »
    »
    14 месяцев назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    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!

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

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

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

    Literally too orz

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

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

    Good observation

»
16 месяцев назад, скрыть # |
 
Проголосовать: нравится -19 Проголосовать: не нравится

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.

»
16 месяцев назад, скрыть # |
 
Проголосовать: нравится +3 Проголосовать: не нравится
»
16 месяцев назад, скрыть # |
 
Проголосовать: нравится +8 Проголосовать: не нравится

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

»
12 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

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

»
12 месяцев назад, скрыть # |
← Rev. 2  
Проголосовать: нравится 0 Проголосовать: не нравится

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/

»
7 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

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

»
7 месяцев назад, скрыть # |
 
Проголосовать: нравится -14 Проголосовать: не нравится

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