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

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

This is the Part-2 of my Bitwise Operations Blog. In this part, I focused more on intermediate-level bitwise tricks, Common CP Patterns and a few slightly advanced techniques that appear frequently in contest. — Part-1 — Click Here
I tried to explain the intuition and thinking process behind each trick as clearly and simple as possible.

And as always, Heartfelt thanks to Raha Ahmed for her endless encouragement, strongest support and constant belief in me !


Core Concepts You Must Understand First :-


Intermediate level Bitwise Problems in CP rarely ask you to just "check" or "set" a bit. Instead, they require you to use the Mathematical Properties of bits to optimize your code. Before we jump into the 8 Master Pattern, you need to firmly understand these 5 core concepts.
If you understand these the upcoming patterns will feels like magic !


Core Explanations - (click here)

Topic 1 : Bit-by-Bit Contribution :-


Explanation - (click here)

Topic 2 : The Equation That Solves Half of Bitwise Math :-


Explanation - (click here)

Topic 3 : The Monotonicity of AND / OR :-


Explanation - (click here)

Topic 4 : Greedy with MSB : Top-Down Approach :-


Explanation - (click here)

Topic 5 : Prefix XOR : The O(1) Range Query Magic :-


Explanation - (click here)

Topic 6 : Submask Enumeration : The Magic Loop :-


Explanation - (click here)

Topic 7 : __builtin_clz and __builtin_ctz Tricks :-


Explanation - (click here)

Topic 8 : Game Theory : The Magic of Nim-Sum :-


Explanation - (click here)


Part-3 (Advanced Bitwise Operations) :-

To be honest, I haven’t completely mastered the most advanced bitwise techniques yet and there is still so much left for me to learn.
So I plan to write a Part-3 in the future when I dive deeper into those advanced topics and feel truly capable of explaining them.
Please keep me in your prayers. Happy journey, Everyone ! Regards :- RS1630


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

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

Aha, Sprague-Grundy theorem for Div2B! That’s why it took me an hour to solve last div2B, because I didn’t know enough useless master level things!

Read the post before upvoting it.. this is slop

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

Really nice content!

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

Very helpful, thanks

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

Part 3 once you reach cm trust

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

Really Helpful. This topic is nightmare for me.

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

This content is extremely helpful, your effort behind writing this post is highly appreciated!

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

ubub <3

Such great content with simple explanations. This topic is terrible :)

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

In Topic 1, surely there's no carry but if we chose bit as 1 in say 3rd position then arent automatically other bits are decided too? as there are only certain numbers with third position as 1 and they have fixed value for other bits.

please clear my doubt!

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

    Good catch! Yes, the bits inside a specific number are fixed. But the magic here is that we arent tracking specific numbers anymore. We are just counting how many (1, 0) pairs exist in the 3rd column across the whole array, calculating their total value and adding it directly to the final sum ! clear brother ?

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

thanks, very helpful

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

very nice blog, enjoyed reading it and also learnt a few new things, that binary search idea in 3rd section was gr8 too, thanks for the blog, cant wait for the part3!

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

It's Easy too.

Hope for Part 3 ;>

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

W content, Loved the Game Theory Part (Nim Sum). (+1) Interested for Part-3!

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

loved it...!❤️

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

Regarding topic 7, consider using the C++ bit manipulation header. This gives you a number of very useful operations, such as the ones mentioned above. Really just read through each operation and I swear your bit manipulation problems will become that much easier/nicer to implement :)

A nice plus from these functions is that:

  • C++ automatically deduces the implementation for each function based on the provided type, so you don't have to worry about putting the lls as the suffix.
  • Also, you're forced to used unsigned types. While this might seem annoying to some, in reality it's very good for type safety. This is due to the fact that when we do bit problems, we generally envision manipulating masks that map on to some non negative integer. So, if that invariant is ever broken we can get unexpected results (well, if we're doing something finicky, which happens a lot in bit manipulation problems).
  • You get more functions! So instead of having to do 1LL << (31 - __builtin_clz(x)), you can just put bit_floor(x) and it works!!! This feature can be used to trivially initialize segment trees. So instead of having to do something like len=1<<(31-__builtin_clz(2*n-1)) to initialize the base length of the segtree, you can just put bit_ceil(x) and that's it! Notice that this point also helps with "code safety", as you have to write less janky code which is easy to mess up.

As a separate note, I really recommend reading through the C++ reference (on cppreference), as you can learn about a number of functions/data structures that are basically just "Quality of Life" features. A few examples:

  • Too lazy to write a two pointers to merge two sets? Use std::merge.
  • Too lazy to write a two pointers to get the intersection of two sets? Use std::set_intersection
  • Need a way to store not necessarily unique sorted items which reference other values? Use std::multimap (I haven't seen a lot of people use it, and some problems are just nicer to implement with this, although of course you could use a multiset which would be a bit slower...)
  • Want to iterate over a map in reverse without having to use explicit reverse iterators? Just do for (auto &[k, v] : your_map | std::views::reverse) { ... }
  • Need to sort your elements in a stable manner (ie, if two elements are equal then they maintain their original relative ordering)? Just use std::stable_sort
  • And so much more
»
5 месяцев назад, скрыть # |
 
Проголосовать: нравится +3 Проголосовать: не нравится

Well done very good blog ;)))

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

I think learning a theory is better when you have a lot of practice problems regarding about the topic to quickly catch the topic and master it . so , I would like to thanks you first and give a suggestion to add problem list or link of list which contains problems < Thanks a lot!

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

    Thanks man ! Thats a great suggestion & I actually thought about it. But finding the perfect practice problems for each topic takes a ton of time & I couldnt manage it this time but ill definitely keep this in mind & try to add a list later on !

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

Thanks for sharing 0t0infinity :)

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

Very well made, I needed to create some notes to quickly get the function, instead of coming up with the approach every single time. Thanks.

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

wtf strong

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

great work (begineer part was also good). btw congratulations on reaching expert

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

What an amazing blog! we want more like these. Whomever I share it with, loved it.

However could you also explain the reason/proof behind the nim-sum being 0 is same as empty game state?

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

    Tahnks Man ! Really glad you liked it !
    An empty game state means all piles are 0, so the XOR sum is naturally 0. But logically an empty board just means you have no moves left to win. A Nim-sum of 0 is the exact same trap ! If the sum is 0, ANY move you make will instantly turn it non-zero. You are basically forced to hand a winning board right back to your opponent.
    So, a Nim-sum of 0 is basically a trap. Whether the board is completely empty or the sum is 0 in both cases, you have zero good moves left and youre stuck. Hope this helps !