Imagine a party where each guest wants a unique cap from a collection, but each guest has preferences on which caps they like. How many ways can you assign caps so that everyone gets a unique cap they like?
Given n persons and 100 caps numbered 1 to 100. Each person has a list of caps they like. Find the number of ways to assign caps to persons such that each person gets exactly one cap they like and no two persons get the same cap. Return the count modulo 10^9+7.
1 ≤ n ≤ 10Each person likes at least one capCaps are numbered from 1 to 100
Edge cases: All persons like the same single cap → output 0Each person likes a unique cap → output 1One person likes all caps, others like none → output 0
def count_ways(person_caps):
# Write your solution here
pass
class Solution {
public int countWays(List<List<Integer>> personCaps) {
// Write your solution here
return 0;
}
}
#include <vector>
using namespace std;
int countWays(const vector<vector<int>>& personCaps) {
// Write your solution here
return 0;
}
function countWays(personCaps) {
// Write your solution here
}
Coming soon
0/9
Common Bugs to Avoid
Wrong: 0Not counting any assignments due to missing memoization or incorrect base case.✅ Add base case returning 1 when all persons assigned and memoize intermediate results.
Wrong: 1Greedy approach assigning first available cap only, missing other permutations.✅ Use full bitmask DP exploring all cap assignments recursively with memoization.
Wrong: Incorrect positive number when unique assignment impossibleNot enforcing unique cap assignment, allowing multiple persons to share same cap.✅ Check bitmask to ensure cap not already assigned before assigning to a person.
Wrong: Timeout or no outputBrute force recursion without memoization causing exponential blowup.✅ Implement memoization or bottom-up DP to prune repeated states.
✓
Test Cases
Focus on handling base cases and minimal inputs correctly.
Watch out for greedy traps and ensure full DP state exploration.
Optimize your DP solution to run efficiently for n=10.
💡 Think about assigning caps one person at a time and track used caps with a bitmask.
💡 Use bitmask DP to represent which caps are already assigned and recurse over persons.
💡 Memoize states by (person index, assigned caps bitmask) to avoid recomputation.
Why it failed: Incorrect count likely due to missing memoization or not checking cap availability before assignment. Fix by adding memo dictionary keyed by (person, mask) and only assign unused caps.
✓ Correctly counts all unique assignments using bitmask DP with memoization.
💡 Try enumerating assignments and track used caps with bitmask.
💡 Check that no two persons share the same cap by verifying bitmask bits.
💡 Use DP with memoization to count all valid assignments efficiently.
Why it failed: Wrong output due to not enforcing unique cap assignment or missing some combinations. Fix by ensuring caps assigned are not already used (check bitmask) before recursive call.
✓ All valid unique cap assignments counted correctly with bitmask DP.
t2_01edge
Input{"person_caps":[]}
Expected1
⏱ Performance - must finish in 2000ms
No persons means one valid assignment (empty assignment).
💡 Consider the base case when no persons are present.
💡 The count of ways to assign caps to zero persons is 1 (empty assignment).
💡 Return 1 when person list is empty as a base case in recursion.
Why it failed: Returning 0 or error on empty input misses base case. Fix by returning 1 when all persons assigned (i == n).
✓ Correctly handles empty input as one valid assignment.
t2_02edge
Input{"person_caps":[[42]]}
Expected1
⏱ Performance - must finish in 2000ms
Single person with one cap liked has exactly one assignment.
💡 Test the simplest non-empty case with one person and one cap.
💡 Ensure the code handles single element arrays and returns 1 if cap is available.
💡 Base case: if person index reaches n, return 1; else try assigning liked caps.
Why it failed: Incorrect output due to off-by-one or missing base case for single person. Fix by correctly returning 1 when all persons assigned.
✓ Correctly counts one assignment for single person single cap.
t2_03edge
Input{"person_caps":[[1],[1],[1]]}
Expected0
⏱ Performance - must finish in 2000ms
All persons like the same single cap; only one cap available, so no unique assignments possible.
💡 Check if multiple persons like only the same cap.
💡 Since caps must be unique per person, only one person can get that cap.
💡 Return 0 if not enough unique caps to assign to all persons.
Why it failed: Output >0 means code does not enforce unique cap assignment. Fix by checking bitmask to avoid assigning already used caps.
✓ Correctly returns 0 when unique assignment impossible due to cap conflicts.
t3_01corner
Input{"person_caps":[[1,2],[1,2],[1,2]]}
Expected0
⏱ Performance - must finish in 2000ms
Three persons all like only caps 1 and 2; only two caps available, so no unique assignment for all three.
💡 Check if number of unique caps liked is less than number of persons.
💡 Bitmask DP must ensure no two persons share the same cap.
💡 If not enough unique caps, result is zero.
Why it failed: Output >0 means code does not check cap uniqueness properly or does not prune impossible states. Fix by pruning states where caps assigned exceed available unique caps.
✓ Correctly returns 0 when unique assignment impossible due to insufficient caps.
t3_02corner
Input{"person_caps":[[1,2,3],[1,2,3],[1,2,3]]}
Expected6
⏱ Performance - must finish in 2000ms
All persons like caps 1, 2, 3; total unique assignments are permutations of 3 caps to 3 persons = 3! = 6.
💡 This tests if code counts all permutations correctly.
💡 Avoid greedy approach that picks first available cap only.
💡 Use full bitmask DP to count all permutations.
Why it failed: Output less than 6 means greedy or incomplete counting. Fix by exploring all cap assignments recursively with memoization.
✓ Correctly counts all permutations of cap assignments.
💡 Check that code does not confuse 0/1 knapsack with unique assignment constraints.
💡 Ensure caps are assigned uniquely and all persons get one cap.
💡 Use bitmask DP to track assigned caps and count all valid assignments.
Why it failed: Output incorrect due to confusing unbounded assignment or missing uniqueness. Fix by enforcing caps assigned only once and exactly one per person.
✓ Correctly counts all unique assignments respecting constraints.
t4_01performance
Input{"_description":"n=10 at constraint boundary - executor generates this input with overlapping caps"}
Expectednull
⏱ Performance - must finish in 2000ms
n=10 persons with overlapping caps; O(100 * 2^n * n) DP expected to run within 2 seconds.
💡 Use bitmask DP with memoization or bottom-up tabulation.
💡 Avoid brute force recursion without memoization to prevent TLE.
💡 Optimize state transitions and prune impossible states early.
Why it failed: TLE indicates exponential brute force without memoization or inefficient state management. Fix by implementing DP with memoization or tabulation.
✓ Efficient DP solution runs within time limits.
Practice
(1/5)
1. Consider the following iterative postorder traversal code snippet for computing the maximum path sum in a binary tree. Given the tree:
1
/ \
2 3
What is the final value of max_sum after the algorithm completes?
easy
A. 4
B. 6
C. 5
D. 3
Solution
Step 1: Trace gains for leaf nodes
Node 2 and Node 3 are leaves, so gains[2] = 2, gains[3] = 3, max_sum updated to max(-inf, 2) = 2, then max(2,3) = 3.
Hint: Sum path through root includes both children gains [OK]
Common Mistakes:
Forgetting to add both children
Using only max child gain
Off-by-one in stack processing
2. Consider the following Python code implementing the optimized LIS algorithm. What is the value of the variable tails after processing the input [3, 1, 2]?
tails always sorted and minimal last elements [OK]
Hint: tails stores smallest possible ends of subsequences [OK]
Common Mistakes:
Appending instead of replacing in tails
Misunderstanding bisect_left index
Confusing tails with actual subsequence
3. What is the time complexity of the iterative postorder traversal solution for the Binary Tree Maximum Path Sum problem, assuming the tree has n nodes?
medium
A. O(n) for traversal but O(n) extra space for the stack and gains dictionary
B. O(n log n) due to repeated stack operations and subtree recomputations
C. O(n^2) because for each node, the algorithm recomputes gains from all descendants
D. O(n) because each node is visited once and gains are computed in constant time per node
Solution
Step 1: Identify traversal cost
The iterative postorder traversal visits each node exactly once, pushing and popping it from the stack once.
Step 2: Analyze per-node computation
At each node, gains are computed using stored values from children in O(1) time, no recomputation of subtrees.
Final Answer:
Option D -> Option D
Quick Check:
Linear traversal with constant work per node -> O(n) time [OK]
Hint: Each node processed once, no repeated subtree work [OK]
Common Mistakes:
Confusing recursion stack with repeated work
Assuming recomputation of subtree gains
Ignoring constant time per node
4. Suppose the problem is modified so that elements can be reused multiple times in subsequences (i.e., subsequences are multisets, not strictly increasing indices). Which change to the DP approach correctly counts all arithmetic subsequences under this new constraint?
hard
A. Keep the same DP but allow j to be equal to i to reuse elements
B. Use a DP that counts subsequences by difference without restricting j < i, allowing repeated indices
C. Modify DP to consider all pairs (i, j) with i ≤ j and update counts accordingly
D. Switch to a combinatorial formula since DP no longer applies
Solution
Step 1: Understand reuse means indices can repeat or be equal
Original DP requires j < i to ensure strictly increasing indices; reuse breaks this.
Step 2: Modify DP loops to allow i ≤ j and update counts accordingly
Allowing i ≤ j and updating dp[i][diff] with dp[j][diff] + 1 counts subsequences with repeated elements correctly.
Step 3: Reject naive reuse of original DP or combinatorial formulas
Original DP with j < i fails; combinatorial formulas are not straightforward here.
Final Answer:
Option C -> Option C
Quick Check:
Allowing i ≤ j and updating counts handles reuse correctly [OK]
Hint: Reuse requires relaxing j < i to i ≤ j in DP loops [OK]
Common Mistakes:
Trying to reuse original DP without index relaxation
Assuming combinatorial formula suffices
Allowing j = i without updating counts properly
5. Suppose the problem changes: now you can reuse elements multiple times to form the longest strictly increasing subsequence. Which modification to the optimized LIS algorithm is correct?
hard
A. The optimized binary search approach cannot be directly adapted; use a DP with memoization considering reuse
B. Modify the DP to consider repeated elements by changing comparison from '>' to '>=' in recursion
C. Use the same binary search approach but allow replacing tails with equal or greater elements (use bisect_right)
D. Sort the array and count the longest consecutive increasing sequence allowing duplicates
Solution
Step 1: Understand reuse impact
Allowing reuse breaks the strictly increasing subsequence definition and the binary search tails logic.
Step 2: Evaluate algorithm suitability
The optimized binary search approach relies on unique progression; reuse requires state tracking, best handled by DP with memoization.
Final Answer:
Option A -> Option A
Quick Check:
Reuse requires more complex DP, not simple binary search [OK]
Hint: Reuse breaks tails logic; DP with memo needed [OK]
Common Mistakes:
Trying to fix with bisect_right only
Changing comparison operators without DP
Assuming sorting solves reuse problem
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.