2240. Number of Ways to Buy Pens and Pencils
Problem Description
You have a certain amount of money (total
) and want to buy pens and pencils. Each pen costs cost1
and each pencil costs cost2
.
Your task is to find how many different ways you can spend your money on these items. You can:
- Buy any number of pens (including zero)
- Buy any number of pencils (including zero)
- Spend part of your money or all of it
- Leave some money unspent
Each unique combination of pens and pencils counts as one distinct way.
For example, if you have total = 20
, cost1 = 10
(pen price), and cost2 = 5
(pencil price), you could:
- Buy 0 pens and 0 pencils
- Buy 0 pens and 1 pencil
- Buy 0 pens and 2 pencils
- Buy 0 pens and 3 pencils
- Buy 0 pens and 4 pencils
- Buy 1 pen and 0 pencils
- Buy 1 pen and 1 pencil
- Buy 1 pen and 2 pencils
- Buy 2 pens and 0 pencils
This gives us 9 distinct ways to make purchases.
The solution works by iterating through all possible numbers of pens you can afford (x
ranges from 0 to total // cost1
). For each number of pens, it calculates how many pencils you can buy with the remaining money: (total - x * cost1) // cost2
. Since you can also choose to buy 0 pencils up to this maximum number, you add 1 to include the zero option. The sum of all these possibilities gives the total number of distinct ways.
Intuition
The key insight is that we can break this problem down by fixing one variable and calculating the possibilities for the other.
Think about it this way: if we decide to buy exactly x
pens, we've already spent x * cost1
dollars. This leaves us with total - x * cost1
dollars for pencils. With this remaining money, we can buy anywhere from 0 to (total - x * cost1) // cost2
pencils.
Why does this enumeration strategy work? Because once we fix the number of pens, the problem becomes one-dimensional - we just need to count how many valid pencil quantities exist. For each fixed number of pens, the number of valid ways equals the maximum number of pencils we can afford plus one (to account for buying zero pencils).
The beauty of this approach is that we avoid checking every possible combination of pens and pencils. Instead of nested loops that would check if x * cost1 + y * cost2 <= total
for all possible (x, y)
pairs, we iterate through pen quantities only once. For each pen quantity, we directly calculate the valid range of pencil quantities using integer division.
This transforms what could be a two-dimensional search space into a series of one-dimensional calculations. We're essentially asking: "If I buy 0 pens, how many pencil options do I have? If I buy 1 pen, how many pencil options remain?" and so on. The sum of all these options gives us our answer.
The formula (total - x * cost1) // cost2 + 1
captures this perfectly - it tells us the count of valid pencil quantities (including zero) for a given number of pens x
.
Learn more about Math patterns.
Solution Approach
The implementation follows a straightforward enumeration strategy where we iterate through all possible quantities of pens and calculate the corresponding number of ways to buy pencils.
We start by initializing a counter ans = 0
to track the total number of distinct ways.
The main loop iterates through all possible quantities of pens: for x in range(total // cost1 + 1)
. Here, x
represents the number of pens we're buying. The upper bound total // cost1 + 1
ensures we consider all affordable quantities of pens, from 0 up to the maximum number we can buy with our total money.
For each fixed number of pens x
, we calculate:
- The money spent on pens:
x * cost1
- The remaining money for pencils:
total - (x * cost1)
- The maximum number of pencils we can buy:
(total - (x * cost1)) // cost2
The number of ways to buy pencils with the remaining money is y = (total - (x * cost1)) // cost2 + 1
. We add 1 because we can choose to buy anywhere from 0 to the maximum number of pencils. Each of these choices represents a distinct way.
We accumulate these counts by adding y
to our answer for each iteration: ans += y
.
The algorithm runs in O(total / cost1)
time complexity since we iterate through at most total // cost1 + 1
values. The space complexity is O(1)
as we only use a constant amount of extra space for variables.
This approach efficiently counts all valid combinations without explicitly generating them, making it both time and space efficient for the given constraints.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example with total = 15
, cost1 = 4
(pen price), and cost2 = 3
(pencil price).
We'll iterate through each possible number of pens and count how many ways we can buy pencils with the remaining money.
Step 1: Buy 0 pens
- Money spent on pens:
0 * 4 = 0
- Money remaining:
15 - 0 = 15
- Maximum pencils affordable:
15 // 3 = 5
- Ways to buy pencils:
5 + 1 = 6
(can buy 0, 1, 2, 3, 4, or 5 pencils) - Running total:
ans = 6
Step 2: Buy 1 pen
- Money spent on pens:
1 * 4 = 4
- Money remaining:
15 - 4 = 11
- Maximum pencils affordable:
11 // 3 = 3
- Ways to buy pencils:
3 + 1 = 4
(can buy 0, 1, 2, or 3 pencils) - Running total:
ans = 6 + 4 = 10
Step 3: Buy 2 pens
- Money spent on pens:
2 * 4 = 8
- Money remaining:
15 - 8 = 7
- Maximum pencils affordable:
7 // 3 = 2
- Ways to buy pencils:
2 + 1 = 3
(can buy 0, 1, or 2 pencils) - Running total:
ans = 10 + 3 = 13
Step 4: Buy 3 pens
- Money spent on pens:
3 * 4 = 12
- Money remaining:
15 - 12 = 3
- Maximum pencils affordable:
3 // 3 = 1
- Ways to buy pencils:
1 + 1 = 2
(can buy 0 or 1 pencil) - Running total:
ans = 13 + 2 = 15
We stop here because buying 4 pens would cost 4 * 4 = 16
, which exceeds our total of 15.
Final Answer: 15 distinct ways
This gives us combinations like:
- (0 pens, 0 pencils), (0 pens, 1 pencil), ..., (0 pens, 5 pencils)
- (1 pen, 0 pencils), (1 pen, 1 pencil), ..., (1 pen, 3 pencils)
- (2 pens, 0 pencils), (2 pens, 1 pencil), (2 pens, 2 pencils)
- (3 pens, 0 pencils), (3 pens, 1 pencil)
Solution Implementation
1class Solution:
2 def waysToBuyPensPencils(self, total: int, cost1: int, cost2: int) -> int:
3 """
4 Calculate the number of ways to buy pens and pencils with given total money.
5
6 Args:
7 total: Total amount of money available
8 cost1: Cost of one pen
9 cost2: Cost of one pencil
10
11 Returns:
12 Number of distinct ways to buy pens and pencils
13 """
14 total_ways = 0
15
16 # Iterate through all possible numbers of pens we can buy
17 max_pens = total // cost1
18 for num_pens in range(max_pens + 1):
19 # Calculate remaining money after buying pens
20 remaining_money = total - (num_pens * cost1)
21
22 # Calculate maximum number of pencils we can buy with remaining money
23 # Add 1 to include the case of buying 0 pencils
24 num_pencil_options = (remaining_money // cost2) + 1
25
26 # Add the number of pencil options for this pen count
27 total_ways += num_pencil_options
28
29 return total_ways
30
1class Solution {
2 /**
3 * Calculate the number of ways to buy pens and pencils with a given total amount.
4 *
5 * @param total The total amount of money available
6 * @param cost1 The cost of each pen
7 * @param cost2 The cost of each pencil
8 * @return The total number of different ways to buy pens and pencils (including buying nothing)
9 */
10 public long waysToBuyPensPencils(int total, int cost1, int cost2) {
11 long totalWays = 0;
12
13 // Iterate through all possible numbers of pens we can buy
14 int maxPens = total / cost1;
15 for (int numPens = 0; numPens <= maxPens; numPens++) {
16 // Calculate remaining money after buying 'numPens' pens
17 int remainingMoney = total - (numPens * cost1);
18
19 // Calculate how many pencils we can buy with the remaining money
20 // Add 1 to include the option of buying 0 pencils
21 int possiblePencilCombinations = (remainingMoney / cost2) + 1;
22
23 // Add the number of pencil combinations for this pen count
24 totalWays += possiblePencilCombinations;
25 }
26
27 return totalWays;
28 }
29}
30
1class Solution {
2public:
3 long long waysToBuyPensPencils(int total, int cost1, int cost2) {
4 long long totalWays = 0;
5
6 // Iterate through all possible quantities of the first item (pens)
7 // Maximum pens we can buy is total / cost1
8 for (int numPens = 0; numPens <= total / cost1; ++numPens) {
9 // Calculate remaining money after buying 'numPens' pens
10 int remainingMoney = total - numPens * cost1;
11
12 // Calculate maximum number of pencils we can buy with remaining money
13 // Add 1 to include the case of buying 0 pencils
14 int numPencilOptions = remainingMoney / cost2 + 1;
15
16 // Add the number of pencil options for this pen quantity
17 totalWays += numPencilOptions;
18 }
19
20 return totalWays;
21 }
22};
23
1/**
2 * Calculates the number of ways to buy pens and pencils with a given total amount
3 * @param total - The total amount of money available
4 * @param cost1 - The cost of each pen
5 * @param cost2 - The cost of each pencil
6 * @returns The number of different ways to buy pens and pencils
7 */
8function waysToBuyPensPencils(total: number, cost1: number, cost2: number): number {
9 let totalWays: number = 0;
10
11 // Iterate through all possible quantities of pens we can buy
12 const maxPens: number = Math.floor(total / cost1);
13
14 for (let pensCount: number = 0; pensCount <= maxPens; ++pensCount) {
15 // Calculate remaining money after buying pens
16 const remainingMoney: number = total - (pensCount * cost1);
17
18 // Calculate how many pencils we can buy with remaining money
19 // Add 1 to include the case of buying 0 pencils
20 const pencilOptions: number = Math.floor(remainingMoney / cost2) + 1;
21
22 // Add the number of pencil options for this pen quantity
23 totalWays += pencilOptions;
24 }
25
26 return totalWays;
27}
28
Time and Space Complexity
The time complexity is O(total / cost1)
. The algorithm iterates through all possible quantities of the first item (pens) that can be purchased, from 0 up to total // cost1
. This gives us at most total / cost1 + 1
iterations. For each iteration, we perform constant time operations: calculating the remaining budget after buying x
pens and determining how many pencils can be bought with that remainder. Since the loop dominates the runtime, the overall time complexity is O(total / cost1)
.
The space complexity is O(1)
. The algorithm only uses a fixed amount of extra space regardless of the input size. We maintain only a few integer variables: ans
for counting valid combinations, x
as the loop counter, and y
for calculating the number of pencils. No additional data structures that grow with the input are used, resulting in constant space complexity.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Integer Overflow in Other Languages
While Python handles large integers automatically, in languages like C++ or Java, calculating num_pens * cost1
could cause integer overflow when dealing with large values.
Solution: Use appropriate data types (like long long
in C++ or long
in Java) or check for overflow conditions before multiplication.
2. Off-by-One Error in Range
A common mistake is forgetting to include either the case where we buy 0 pens or the maximum number of pens we can afford. Writing range(total // cost1)
instead of range(total // cost1 + 1)
would miss the case where we spend all our money on pens.
Solution: Always include both boundaries - start from 0 pens and go up to and including total // cost1
.
3. Forgetting the Zero Purchase Option for Pencils
When calculating the number of ways to buy pencils, developers might return just remaining_money // cost2
without adding 1, forgetting that buying 0 pencils is also a valid option.
Solution: Always add 1 to account for the option of buying 0 pencils: (remaining_money // cost2) + 1
.
4. Attempting to Optimize by Swapping cost1 and cost2
Some might try to optimize by ensuring cost1 >= cost2
to minimize iterations. However, this adds unnecessary complexity and could introduce bugs if not handled carefully with the variable swapping logic.
Solution: Keep the solution simple and straightforward. The performance difference is negligible for reasonable input sizes, and clarity is more important than minor optimizations.
5. Using Nested Loops Unnecessarily
Beginners might use two nested loops to iterate through both pens and pencils explicitly, which would result in O(n²) time complexity:
# Inefficient approach - avoid this
for pens in range(total // cost1 + 1):
for pencils in range(total // cost2 + 1):
if pens * cost1 + pencils * cost2 <= total:
total_ways += 1
Solution: Use the mathematical approach shown in the correct solution where we calculate the number of valid pencil options directly for each pen count, achieving O(n) complexity.
A heap is a ...?
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 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
Want a Structured Path to Master System Design Too? Don’t Miss This!