Modular Code | Observations | Visualisation
Here's how i visualised the solution :Calculation of no. of setbits at a position i for numbers from 0 to x
consider (0 based), cycle starts at 0
f(i,x) = 2^i *
Here's how i visualised the solution : 

![image.png](https://assets.leetcode.com/users/images/54ddb9d7-562d-4bc3-9852-7d335824650b_1738912096.8842747.png)

### Calculation of no. of setbits at a position i for numbers from 0 to x
- consider (0 based), cycle starts at 0
- `f(i,x) = 2^i * (x+1)/(2^(i+1)) + max(0,(x+1)%(2^(i+1)) - 2^i)`
- `f(i,x)= set bits in each cycle * no. of cycles + remaining`
    - remaining =`max(0,(x % no. of cycles)` - unset bits in each cycle
    - set bits = unset bits = `2^i`  in each cycle


# Code
```python3 []
'''
1. big_nums is formed from 1's
2. f(i,x) - no of setbits at ith position in all numbers from 0->x
3. binary search on ∑f(i,x) to get the num contains the position of 'from' and 'to'
4. consider 3 segments - partia(leftNum) + [leftNum+1 + ... + rightNum-1] + partial(rightNum)
5. carefully preform bit manipulations if you are doing << or >> to check for 0th bit
    ((num>>i)&1) - this is correct
    (num&(1<<i)) - this is wrong
6. the answer is some power of 2 with mod as all the elements of big_nums are powers of 2
7. we just need to find the power of 2 which is the sum of set bits in the range(from,to)
'''
class Solution:
    maxBits=50
    # returns no. of set bits i->[0,..),x->[0,...)
    def getSetBitsAtPos(self,i,x): return (1<<i)*((x+1)//(1<<(i+1))) + max(0,(x+1)%(1<<(i+1))-(1<<i))

    def getNum(self,low,high,k,ans):
        while low<=high:
            mid=low+((high-low)>>1)
            cnt=sum(self.getSetBitsAtPos(i,mid) for i in range(self.maxBits))
            if cnt>=k:
                ans=mid
                high=mid-1
            else:
                low=mid+1
        return ans

    def getPos(self,reqBits,currNum):
        currBits=sum(self.getSetBitsAtPos(i,currNum) for i in range(self.maxBits))
        diff=reqBits-currBits
        currNum+=1
        for pos in range(self.maxBits):
            diff-=(currNum>>pos)&1
            if diff==0:return pos
        return 0

    def findProductsOfElements(self, queries):
        res=[]
        for left,right,mod in queries:
            left+=1
            right+=1
            leftNum=self.getNum(0,int(1e15),left,0)
            leftPos=self.getPos(left,leftNum-1)
            leftRem=(leftNum>>leftPos)<<leftPos
            # print(leftNum,leftPos,leftRem)
            
            rightNum=self.getNum(0,int(1e15),right,0)
            rightPos=self.getPos(right,rightNum-1)
            rightRem=0
            for i in range(rightPos+1):rightRem|=(1<<i)&rightNum
            # print(rightNum,rightPos,rightRem)
            
            bitsCount=sum(i*(
                self.getSetBitsAtPos(i,rightNum-1) - self.getSetBitsAtPos(i,leftNum) # middleSetBits    
                + ((leftRem>>i)&1) + ((rightRem>>i)&1)
            ) for i in range(self.maxBits))
            # print(bitsCount)

            res.append(pow(2,bitsCount,mod))
        return res

```

Thank You @vivgupta98
['Binary Search', 'Bit Manipulation', 'Counting', 'Prefix Sum', 'Python3']