Hi Codeforces! This is my first blog here, so please excuse any rookie formatting or style issues. I’ve been learning Dynamic Programming recently, and I’m currently trying to deepen my understanding of top-down → bottom-up conversion — not just for this problem, but conceptually. I am assuming that my top down code is conceptually sound and correctly implemented, but I am getting WA for the iterative / bottom-up version
Problem
The problem is Maximum Tip Calculator (GFG)
You’re given n orders and two delivery boys — A and B. Each order i gives:
arr[i] → tip if A takes it
brr[i] → tip if B takes it
A can take at most x orders, B can take at most y. We want to maximize the total tip.
I already solved it using the greedy approach (sorting by |arr[i] — brr[i]|), but I wanted to approach it using Dynamic Programming.
My Memoized (Top-Down) Solution:
long long getMaxTip(int idx, int aCount, int x, int y, vector<int> &arr, vector<int> &brr, vector<vector<long long> > &memo){
// No item left to process, means no profit
if(idx >= arr.size()){
return 0;
}
if(memo[idx][aCount] != -1){
return memo[idx][aCount];
}
long long aProfit = 0, bProfit = 0;
//A takes the order
if(aCount < x){
aProfit = 1LL * arr[idx] + getMaxTip(idx + 1, aCount + 1, x, y, arr, brr, memo);
}
//B takes the order
if(idx - aCount < y){
bProfit = 1LL * brr[idx] + getMaxTip(idx + 1, aCount, x, y, arr, brr, memo);
}
return memo[idx][aCount] = max(aProfit, bProfit);
}
//State meaning:
//memo[idx][aCount] = max total profit achievable after processing 'idx' total orders and A has already taken aCount orders. (Though it stores the answer for the lower half of the tree (idx -> n - 1))
Bottom-Up Conversion
Now, I tried converting this to an iterative version , O(N^x) space and O(N*x) time— keeping the exact same state definition and recurrence structure.
Reasoning for the code:
In memoized recursion, subproblems come from deeper calls (idx onwards).
So in bottom-up, we should fill from idx = n-1 → 0.
Each state {idx, aCount} depends on {idx + 1, aCount} and {idx + 1, aCount + 1}.
long long getMaxTipDP2D(int x, int y, vector<int> &arr, vector<int> &brr){
int n = arr.size();
// state {idx, aCount} = max profit made if we have processed (n - idx - 1) items and A has already taken aCount orders;
vector<vector<long long> > dp(n + 1, vector<long long>(x + 1, -1));
//base case(from memo code, when idx == n, the profit = 0)
for(int j = 0; j <= x; j++){
dp[n][j] = 0;
}
for(int idx = n - 1; idx >= 0; idx--){
int totalItemsProcessed = n - idx - 1;
for(int aCount = 0; aCount <= min(x, totalItemsProcessed); aCount++){
//current state to fill => {idx, aCount}
long long aProfit = 0, bProfit = 0;
// A can take order iff range[0, min(totalItems,x))
// B can take order iff range[0, y)
//Boundary case check
if(aCount < x){
aProfit = 1LL * arr[idx] + dp[idx + 1][aCount + 1];
}
//Total Items proccessed till now - orders A have taken already
if(totalItemsProcessed - aCount < y){
bProfit = 1LL * brr[idx] + dp[idx + 1][aCount];
}
//Answer of current state
dp[idx][aCount] = max(aProfit, bProfit);
}
}
long long res = 0;
for(int j = 0; j <= x; j++){
res = max(res, dp[0][j]);
}
return res;
}
//State meaning (bottom-up):
//dp[idx][aCount] = max profit made from processing (n - idx - 1) items if A has already taken aCount orders.
❓ My Question
Now, here’s where I’m confused conceptually.
Even if this version might not pass large inputs, I’m curious conceptually:
If I directly mirror the recurrence and keep the same DP state meaning (dp[idx][aCount] = answer of subproblem starting at idx), Is there something fundamentally wrong with this kind of conversion? Or should the state meaning itself change when moving to an iterative representation?
Are my top-down and bottom-up definitions actually identical?
In the memoized version, the subproblem is defined as:
“max profit after processing idx items and A has taken aCount orders” but it stores the answer for the later half (from idx → n-1).
In the iterative version, the subproblem is defined as:
“max profit after processing (n — idx — 1) items and A has taken aCount orders,” and it also stores the answer for the later half.
So, my definitions are slightly different in wording — one counts how many items have been processed so far, the other counts how many remain — yet they both seem to represent the same portion of the problem space / recursive tree logically.
In other words, the definition is different, but the meaning feels the same.
Am I right in thinking that both are just two perspectives of the same state? Or does this verbal mismatch actually affect the correctness or iteration order of the DP?
What I’m Hoping to Learn
I’d really appreciate if someone could explain:
Whether my iterative logic is conceptually consistent with the recursive recurrence, and
If not, what conceptual correction (in meaning, iteration order, or indexing) is needed to make it work cleanly when going bottom-up.
I’m more interested in the transition reasoning & sub problems (definition & actual meaning) than just the final optimized code (though that’s welcome too! :)).








Auto comment: topic has been updated by fastrail08 (previous revision, new revision, compare).
If you want to become master in DP then prefer this series. Contains 12 different DP Patterns (1D To Graph DP). 160+ DP problems in which 115+ are from LeetCode. Which means by the end of this series you'll end up solving 115+ DP problems of LeetCode. Its for free on LeetCode: https://leetcode.com/discuss/interview-question/5659029/ultimate-dynamic-programming-series-on-leetcode
Thank you so much for listing a good source of well commented editorials. I skimmed over some editorials of questions that I have already solved :D and found the explanations easy to understand. I will definitely use it as a guide to solve a pattern specific question.
Although, if you don't mind me asking, could you provide any hints or explanation, on why my bottom up code seems to be giving WA. Thanks for the help!
Provide your whole Top Down code (means dp array with size initialization, first call made to getMaxTip() with paramteres, etc). Provide this and I'll give you your bottom-up.
Thanks for the code :D. Could you please tell 2 things:
1) meaning of DP[i][aCount] in your code?
2) could you explain the part where you did:
if(i - aCount < y){}'i' here should represent the totalItems already processed and the whole expression should check if B could take anymore orders
But as we are moving from (n -> 0), does
inot represent the items that are yet to be processed and(n - i - 1)are already proccessed.totalItemsAlreadyProccessed - #orders by A = #orders by Bi.e. the 'if' should be:
if((n - i - 1) - x < y){}Bro I converted your top-down to bottom-up that's it. Don't worry I am starting my DP series on YouTube from December 10 or 15, currently creating lectures, so you just need to keep up with the series till the end and Bottom-up creation will become an easy-peasy work for you. No matter 5D, 6D, etc tabulation, you will do all of them easy-peasy.
here 12 dp patterns video lectures: https://www.youtube.com/playlist?list=PLiF6lAo--At1-wfJi5qwVxqwAsSEOkDMK