3792. Sum of Increasing Product Blocks 🔒
Problem Description
You are given an integer n.
A sequence is built using blocks, where each block is formed by multiplying together a set of consecutive integers. The rules for constructing the blocks are as follows:
- The
1stblock contains1. This is the product of the first1consecutive integer, which is just1. - The
2ndblock contains2 * 3. This is the product of the next2consecutive integers, which are2and3. - The
3rdblock would contain4 * 5 * 6. This is the product of the next3consecutive integers. - In general, the
ithblock is the product of the nexticonsecutive integers, picking up right where the previous block left off.
To understand how the integers are distributed:
- Block
1uses the integer1(1 number). - Block
2uses the integers2, 3(2 numbers). - Block
3uses the integers4, 5, 6(3 numbers). - Block
4uses the integers7, 8, 9, 10(4 numbers).
Each block consumes consecutive integers starting from where the previous block ended, with the ith block consuming exactly i integers.
Let F(n) be the sum of the values of the first n blocks. For example, F(3) would be calculated as:
F(3) = (1) + (2 * 3) + (4 * 5 * 6) = 1 + 6 + 120 = 127
Because the products can grow extremely large, you must return the value of F(n) modulo 10^9 + 7.
How We Pick the Algorithm
Why Simulation / Basic DSA?
This problem maps to Simulation / Basic DSA through a short path in the full flowchart.
Computing blocks of consecutive integer products and summing them modulo MOD is a direct simulation of the described block construction.
Open in FlowchartIntuition
The key observation is that the problem describes a very clear, step-by-step construction process, and we can follow it directly. There's no hidden trick or clever formula needed — we just need to faithfully simulate what the problem describes.
Let's think about what information we need to build each block:
-
For the
ithblock, we need to know which integer to start from. Notice that the starting integer of each block depends on how many integers were consumed by all the previous blocks. Since block1uses1number, block2uses2numbers, and so on, the total numbers used before blockiis1 + 2 + ... + (i - 1). -
Instead of recomputing this sum every time, we can keep a running pointer (let's call it
k) that always points to the first integer of the current block. After finishing a block of sizei, we simply advance the pointer byi, so it lands exactly on the start of the next block.
With the starting point known, building each block is straightforward: we multiply together i consecutive integers beginning at k. We accumulate each block's product into a running total to compute F(n).
The only complication is that these products grow very fast — factorial-like growth — and would quickly overflow into enormous numbers. To handle this, we rely on a property of modular arithmetic: taking the modulo at every multiplication step gives the same result as taking it only at the end. So we apply % (10^9 + 7) during each multiplication and each addition. This keeps all intermediate values small and manageable while preserving the correct final answer.
In short, the intuition is: track the starting integer with a moving pointer, multiply the consecutive integers for each block, sum them up, and keep everything under control using modulo at every step.
Pattern Learn more about Math patterns.
Solution Approach
Solution 1: Simulation
We directly simulate the construction of each block and accumulate the products into the answer. The implementation uses simple variables and two nested loops — no advanced data structures are required.
Let's walk through the implementation step by step:
-
Initialize the variables.
ans = 0holds the running sumF(n).mod = 10**9 + 7is the modulus we apply throughout.k = 1is the pointer to the first integer of the current block. It starts at1because the very first block begins with the integer1.
-
Loop over each block. We iterate
ifrom1ton(inclusive). Hereirepresents both the block index and the number of integers that block contains. -
Compute the product of the current block.
- We set
x = 1as the starting value for the product. - We loop
jover the range[k, k + i), which gives exactly theiconsecutive integers belonging to this block. - For each
j, we updatex = (x * j) % mod. Applying the modulo at every multiplication keepsxsmall and prevents overflow into huge numbers.
- We set
-
Add the block's product to the answer.
- We update
ans = (ans + x) % mod, again taking the modulo to keep the sum bounded.
- We update
-
Advance the pointer.
- We do
k += iso thatknow points to the first integer of the next block. This is what links the blocks together — each one picks up exactly where the previous one ended.
- We do
-
Return the result. After processing all
nblocks,ansholdsF(n)modulo10^9 + 7, which we return.
Complexity Analysis:
- Time complexity: The outer loop runs
ntimes, and for blockithe inner loop runsitimes. The total number of multiplications is1 + 2 + ... + n, which isO(n^2). - Space complexity:
O(1), since we only use a few scalar variables regardless of the input size.
Example Walkthrough
Let's trace through the solution approach with a small example: n = 4. We want to compute F(4) = (1) + (2 * 3) + (4 * 5 * 6) + (7 * 8 * 9 * 10).
Initial Setup:
ans = 0(running sum)mod = 10^9 + 7k = 1(pointer to the first integer of the current block)
Now we loop i from 1 to 4.
Iteration i = 1 (block of size 1):
- Start product
x = 1. - Inner loop
jranges over[1, 1 + 1) = [1, 2), so justj = 1.x = (1 * 1) % mod = 1
- Add to answer:
ans = (0 + 1) % mod = 1 - Advance pointer:
k = 1 + 1 = 2
Block 1 contributes 1. Pointer now sits at 2.
Iteration i = 2 (block of size 2):
- Start product
x = 1. - Inner loop
jranges over[2, 2 + 2) = [2, 4), soj = 2, 3.x = (1 * 2) % mod = 2x = (2 * 3) % mod = 6
- Add to answer:
ans = (1 + 6) % mod = 7 - Advance pointer:
k = 2 + 2 = 4
Block 2 contributes 6. Pointer now sits at 4.
Iteration i = 3 (block of size 3):
- Start product
x = 1. - Inner loop
jranges over[4, 4 + 3) = [4, 7), soj = 4, 5, 6.x = (1 * 4) % mod = 4x = (4 * 5) % mod = 20x = (20 * 6) % mod = 120
- Add to answer:
ans = (7 + 120) % mod = 127 - Advance pointer:
k = 4 + 3 = 7
Block 3 contributes 120. Pointer now sits at 7.
Iteration i = 4 (block of size 4):
- Start product
x = 1. - Inner loop
jranges over[7, 7 + 4) = [7, 11), soj = 7, 8, 9, 10.x = (1 * 7) % mod = 7x = (7 * 8) % mod = 56x = (56 * 9) % mod = 504x = (504 * 10) % mod = 5040
- Add to answer:
ans = (127 + 5040) % mod = 5167 - Advance pointer:
k = 7 + 4 = 11
Block 4 contributes 5040. Pointer now sits at 11.
Final Result:
After all 4 iterations, ans = 5167. We return 5167.
Let's verify: 1 + 6 + 120 + 5040 = 5167. ✓
Key takeaways from this trace:
- The pointer
ksmoothly carries us from one block to the next (1 → 2 → 4 → 7 → 11), so we never recompute where a block starts. - The values consumed by each block are exactly
iconsecutive integers, matching the problem's distribution rule. - Because the numbers here are small, no actual reduction happened at the
% modsteps — but for largen, that modulo is what keeps the products from exploding.
Solution Implementation
1class Solution:
2 def sumOfBlocks(self, n: int) -> int:
3 MOD = 10**9 + 7
4
5 total = 0 # Running sum of all block products
6 start = 1 # Starting integer of the current block
7
8 # Build n blocks; the i-th block contains i consecutive integers
9 for block_size in range(1, n + 1):
10 product = 1 # Product of integers within the current block
11
12 # Multiply the block_size consecutive integers beginning at `start`
13 for value in range(start, start + block_size):
14 product = (product * value) % MOD
15
16 # Accumulate this block's product into the total
17 total = (total + product) % MOD
18
19 # Move the start pointer past the integers used in this block
20 start += block_size
21
22 return total
231class Solution {
2 public int sumOfBlocks(int n) {
3 // Modulus value to prevent integer overflow
4 final int MOD = (int) 1e9 + 7;
5
6 // Accumulator for the final answer
7 long answer = 0;
8
9 // Starting number for the current block
10 int blockStart = 1;
11
12 // Iterate over each block, where block i contains i consecutive numbers
13 for (int block = 1; block <= n; ++block) {
14 // Product of all numbers within the current block
15 long product = 1;
16
17 // Multiply the consecutive numbers in this block:
18 // from blockStart to blockStart + block - 1
19 for (int num = blockStart; num < blockStart + block; ++num) {
20 product = product * num % MOD;
21 }
22
23 // Add the current block's product to the answer
24 answer = (answer + product) % MOD;
25
26 // Advance the starting number for the next block
27 blockStart += block;
28 }
29
30 return (int) answer;
31 }
32}
331class Solution {
2public:
3 int sumOfBlocks(int n) {
4 // Modulo to keep results within int range and avoid overflow.
5 const int kMod = 1e9 + 7;
6
7 // Accumulated sum of all block products.
8 long long ans = 0;
9
10 // Starting integer of the current block.
11 int start = 1;
12
13 // Iterate over each block; block i contains i consecutive integers.
14 for (int i = 1; i <= n; ++i) {
15 // Product of the i integers in the current block.
16 long long product = 1;
17
18 // Multiply integers from 'start' to 'start + i - 1'.
19 for (int j = start; j < start + i; ++j) {
20 product = product * j % kMod;
21 }
22
23 // Add this block's product to the running total.
24 ans = (ans + product) % kMod;
25
26 // Advance the start to the first integer of the next block.
27 start += i;
28 }
29
30 return static_cast<int>(ans);
31 }
32};
331/**
2 * Computes the sum of the products of consecutive integer blocks, modulo 1e9 + 7.
3 *
4 * The integers 1, 2, 3, ... are partitioned into blocks where:
5 * - Block 1 contains 1 number,
6 * - Block 2 contains 2 numbers,
7 * - Block i contains i numbers,
8 * and the numbers are taken in increasing order.
9 *
10 * For each block, the product of its numbers is computed, and all block
11 * products are summed together.
12 *
13 * @param n The number of blocks to process.
14 * @returns The sum of block products modulo 1e9 + 7.
15 */
16function sumOfBlocks(n: number): number {
17 const MOD = 1_000_000_007;
18
19 // `blockStart` is the first integer of the current block.
20 let blockStart = 1;
21
22 // `answer` accumulates the sum of all block products.
23 let answer = 0;
24
25 // Iterate over each block from 1 to n; block `i` contains `i` integers.
26 for (let i = 1; i <= n; i++) {
27 // `blockProduct` holds the product of the integers in the current block.
28 let blockProduct = 1;
29
30 // Multiply the `i` consecutive integers starting at `blockStart`.
31 for (let value = blockStart; value < blockStart + i; value++) {
32 blockProduct = (blockProduct * value) % MOD;
33 }
34
35 // Add this block's product to the running total.
36 answer = (answer + blockProduct) % MOD;
37
38 // Advance the start index to the beginning of the next block.
39 blockStart += i;
40 }
41
42 return answer;
43}
44Time and Space Complexity
-
Time Complexity:
O(n^2)The outer loop runs from
i = 1ton, so it executesntimes. For each iterationi, the inner loop runs fromktok + i, meaning it performs exactlyiiterations. Therefore, the total number of operations is1 + 2 + 3 + ... + n = n(n+1)/2, which simplifies toO(n^2). -
Space Complexity:
O(1)The algorithm only uses a constant number of variables (
ans,mod,k,x,i,j), regardless of the input sizen. No additional data structures that scale withnare allocated, so the space complexity isO(1).
Pattern Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Applying the modulo too late (or forgetting it entirely on the product)
The most common mistake is computing each block's product without applying the modulo at every multiplication, and only taking the modulo when adding to the total:
# WRONG: product is allowed to grow unbounded
for value in range(start, start + block_size):
product = product * value # no modulo here!
total = (total + product) % MOD # modulo applied too late
Why it's a problem:
- In languages with fixed-width integers (C++, Java, Go, etc.), the product overflows a 64-bit integer very quickly — even a handful of blocks produces values far larger than
2^63. The result silently wraps around and becomes incorrect. - In Python, integers are arbitrary precision, so the answer stays correct, but the unbounded products become enormous. Multiplying multi-thousand-digit numbers is slow, turning an otherwise manageable computation into a performance bottleneck.
Solution: Apply the modulo at every multiplication so each intermediate value stays bounded below 10^9 + 7:
for value in range(start, start + block_size):
product = (product * value) % MOD # modulo every step
This keeps each operand small (a product of two numbers < 10^9 + 7 fits comfortably in 64 bits), which is both correct and fast.
Pitfall 2: Mismanaging the start pointer between blocks
A second frequent error is incorrectly advancing the pointer that tracks where each block begins. Two typical variants:
# WRONG: resetting start, so every block begins at 1
for block_size in range(1, n + 1):
start = 1 # bug: should persist across iterations
...
# WRONG: advancing by the wrong amount
start += 1 # bug: should advance by block_size
Why it's a problem:
The blocks are defined to consume consecutive integers, each block picking up exactly where the previous one left off. Resetting start makes every block reuse the integers 1, 2, 3, ...; advancing by 1 instead of block_size causes the blocks to overlap. Both yield the wrong sum.
Solution: Initialize start = 1 once before the loop, and after finishing block i advance it by exactly the number of integers consumed:
start += block_size # exactly block_size integers were used
Pitfall 3: Initializing the product to 0 instead of 1
product = 0 # WRONG: anything multiplied by 0 is 0
for value in range(start, start + block_size):
product = (product * value) % MOD
Why it's a problem: The product is built up via repeated multiplication, so the identity element must be 1. Starting at 0 forces every block's product to 0, making F(n) always 0.
Solution: Initialize product = 1 at the start of each block, since 1 is the multiplicative identity. Note this is distinct from total, which is built by addition and therefore correctly starts at 0.
Pitfall 4: Off-by-one in the range bounds
# WRONG: produces block_size + 1 integers
for value in range(start, start + block_size + 1):
...
Why it's a problem: Block i must contain exactly i integers. Using start + block_size + 1 as the upper bound includes one extra integer, while start + block_size - 1 omits one. Both shift every subsequent block and corrupt the sum.
Solution: Use range(start, start + block_size). Because Python's range is half-open (excludes the upper bound), this yields precisely block_size integers: start, start + 1, ..., start + block_size - 1.
Ready to land your dream job?
Unlock your dream job with a 5-minute quiz for a personalized study roadmap!
Get My RoadmapWhich of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Want a Structured Path to Master System Design Too? Don’t Miss This!