Level 5 — Prefix, Difference, Contribution (আগে থেকে হিসেব করে রাখার জাদু)¶
দোকানদার প্রতিবার গ্রাহক এলে গোটা খাতা যোগ করে না — সে একটা running total রাখে। এই level-এর পুরোটাই সেই বুদ্ধি: একবার কষ্ট করে precompute করো, তারপর প্রতিটা query-র উত্তর দাও চোখের পলকে। Prefix sum, difference array, আর contribution — তিনটা কৌশল, একটাই দর্শন: কাজটা আগেই করে রাখো।
এই level এ কী শিখবে?¶
মূল idea গুলো:
- Prefix sum — running total-এর array;
sum(l..r) = P[r] - P[l-1]— ফিতা কেটে মাপার ছবি - Difference array — prefix sum-এর উল্টো অপারেশন; range update মানে শুধু দুই প্রান্তে দাগ (
l-এ +x,r+1-এ -x) - Prefix XOR — যোগের জায়গায় XOR বসালেও একই কৌশল চলে (Level 4-এর XOR ফিরে আসে!)
- 2D prefix sum — rectangle-এর sum, inclusion-exclusion-এর ছবি দিয়ে
- Prefix + hash map — "P[r] - K কি আগে দেখেছি?" — subarray sum = K এক pass-এ
- Prefix mod K — divisible subarray গোনা; একই remainder-এর জোড়া মানেই উত্তর
- Contribution technique — subarray ধরে না গুনে প্রতিটা element-কে জিজ্ঞেস করা: "তুমি কয়টা subarray-তে আছ?"
- Imos method আর sweep line — event-ভিত্তিক +1/-1 দাগ দিয়ে timeline-এর হিসাব
কেন এই level দরকার?¶
Competitive programming (CP) এ: prefix sum হলো CP-র সবচেয়ে বেশি ব্যবহৃত precomputation — CSES, Codeforces Div 2-এর A/B/C-তে এটা ছাড়া চলা যায় না। Difference array আর imos method ছাড়া range update problem-এ TLE নিশ্চিত। আর contribution technique হলো "sum over all subarrays" ঘরানার প্রতিটা problem-এর মাস্টার কী।
Interview এ: Subarray Sum Equals K হলো অন্যতম জনপ্রিয় interview problem — prefix + hash map-এর combo টা Two Sum-এরই বড় ভাই। Range Sum Query, 2D matrix sum, Sum of Subarray Minimums — সবগুলোই common interview pattern।
পরের ধাপে: sliding window (Level 6) আসলে prefix-চিন্তারই গতিশীল রূপ; segment tree আর BIT হলো prefix sum-এর "update-ও করা যায়" version; sweep line থেকে interval problem-এর পুরো জগত খোলে।
Prerequisites¶
- Level 0: Absolute Basics — loop আর array-তে স্বচ্ছন্দ হওয়া
- Level 2: Modular Arithmetic — problem 074-এ
P mod Kলাগবে - Level 4: Bit Manipulation — problem 071-এ XOR-এর self-inverse ধর্ম লাগবে
- Hash map (Python
dict) basics — problem 073/074-এ; গভীরে যেতে ../../05-hashing/ পরে আছে
Learning goals (checklist)¶
এই level শেষে নিজেকে জিজ্ঞেস করো:
- [ ] Prefix array বানিয়ে
sum(l..r) = P[r] - P[l-1]— off-by-one ভুল ছাড়া লিখতে পারি - [ ] কেন
P[l-1]বাদ দিতে হয় (l না) — ফিতার ছবি এঁকে বলতে পারি - [ ] Difference array-তে একটা range update মানে ঠিক 2টা লেখা — এই দাবিটা ব্যাখ্যা করতে পারি
- [ ] Prefix XOR দিয়ে range XOR query — যোগের বদলে XOR কেন একই template-এ চলে, জানি
- [ ] 2D prefix-এর 4-term formula (inclusion-exclusion) ছবি দেখে নিজে বের করতে পারি
- [ ] Subarray Sum = K-তে hash map-এ কী রাখি, কখন count বাড়াই — পরিষ্কার
- [ ]
prefix[0] = 0-এর base entry (hash map-এ{0: 1}) কেন লাগে, বুঝি - [ ] Contribution-এ
(i + 1) * (n - i)formula-টা আঁকতে পারি — বাঁয়ে কত পছন্দ, ডানে কত পছন্দ - [ ] Imos method-এ event থেকে difference array — অন্তত একটা উদাহরণ হাতে চালিয়েছি
- [ ] Sweep line-এ +1/-1 event sort করে "একসাথে সর্বোচ্চ কয়জন" বের করতে পারি
Problem list¶
মোট 14টা problem — 2টা Easy, 11টা Medium, 1টা Hard।
Easy¶
| # | Problem | Pattern | Source |
|---|---|---|---|
| 067 | Prefix Sum | running total | LeetCode Range Sum Query Immutable — https://leetcode.com/problems/range-sum-query-immutable/, CSES Static Range Sum Queries — https://cses.fi/problemset/task/1646 |
| 068 | Range Sum Query | P[r]-P[l-1] | একই source 067-এর মতো |
Medium¶
| # | Problem | Pattern | Source |
|---|---|---|---|
| 069 | Difference Array | range update | Classic technique (USACO Guide silver) |
| 070 | Range Update Query | diff + prefix | Classic exercise |
| 071 | Prefix XOR | XOR prefix | CSES Range Xor Queries — https://cses.fi/problemset/task/1650 |
| 072 | 2D Prefix Sum | rectangle I-E | LeetCode Range Sum Query 2D — https://leetcode.com/problems/range-sum-query-2d-immutable/, CSES Forest Queries — https://cses.fi/problemset/task/1652 |
| 073 | Subarray Sum Equals K | prefix + hash map | LeetCode — https://leetcode.com/problems/subarray-sum-equals-k/ |
| 074 | Count Subarrays Divisible by K | prefix mod count | LeetCode Subarray Sums Divisible by K — https://leetcode.com/problems/subarray-sums-divisible-by-k/, CSES Subarray Divisibility — https://cses.fi/problemset/task/1662 |
| 075 | Contribution Technique Basic | per-element counting | Classic CP technique |
| 076 | Sum of All Subarrays | (i+1)*(n-i) | Classic CP exercise |
| 078 | Pair Contribution Problems | per-pair counting | Classic CP exercise |
| 079 | Imos Method Basic | event difference | Classic technique (imos method) |
| 080 | Sweep Line Intro | +1/-1 events | Classic technique |
Hard¶
| # | Problem | Pattern | Source |
|---|---|---|---|
| 077 | Sum of Subarray Minimums | contribution + spans | LeetCode — https://leetcode.com/problems/sum-of-subarray-minimums/ |
পুরো tracker table (status সহ) আছে problems/README.md-তে।
Recommended order¶
- 067 → 068 — আগে running total বানাও, তারপর সেটা দিয়ে query-র উত্তর; এটাই পুরো level-এর ভিত
- 069 → 070 — উল্টো দিক: query না, এবার update; difference array-র দুই-দাগের কৌশল
- 071 — যোগের জায়গায় XOR বসিয়ে দেখো — template এক, operator ভিন্ন
- 072 — এক dimension থেকে দুই dimension; inclusion-exclusion-এর ছবিটা এখানে আঁকতেই হবে
- 073 → 074 — prefix-এর সাথে hash map-এর বিয়ে; 073 হলো এই level-এর তারকা problem
- 075 → 076 — দৃষ্টিভঙ্গি উল্টাও: subarray না গুনে element গোনো
- 078 — contribution-এর pair version
- 077 — সবচেয়ে কঠিন; contribution + "কতদূর পর্যন্ত আমি minimum" — monotonic stack-এর গন্ধ
- 079 → 080 — শেষে imos আর sweep line; difference-চিন্তা event-এর জগতে
Common mistakes (সাধারণ ভুল)¶
- Off-by-one:
P[r] - P[l]লিখে ফেলা — l-তম element-টাও বাদ পড়ে যায়! বিয়োগ করতে হয়P[l-1](0-indexed prefix-এ:P[r+1] - P[l], যেখানেP-র দৈর্ঘ্য n+1)। Convention একটা বেছে নিয়ে সেটাতেই থাকো। P[0] = 0-এর sentinel ভুলে যাওয়া — দৈর্ঘ্য n+1-এর prefix array না বানালেl = 0-এর query-তে আলাদা if লাগে; sentinel থাকলে formula সব জায়গায় এক।- Hash map-এ
{0: 1}initialize না করা — Subarray Sum = K-তে যে subarray index 0 থেকে শুরু, সেটা গোনা হবে না। এটা এই problem-এর #1 bug। - Difference array-তে
r+1লিখতে ভুলে যাওয়া —diff[l] += xদিলেdiff[r+1] -= x-ও দিতে হবে, নইলে update টা array-র শেষ পর্যন্ত গড়িয়ে যায়। আরr+1যেন array-র বাইরে না যায় — সেজন্য diff-টা এক ঘর বড় রাখো। - Python-এ negative mod নিয়ে নিশ্চিন্ত থেকে অন্য ভাষায় ফাঁদে পড়া — Python-এ
-3 % 5 = 2(সুবিধাজনক!), কিন্তু C++/Java-তে negative আসে। 074-এ remainder normalize করার অভ্যাসটা রাখো। - Contribution-এ
(i + 1) * (n - i)আরi * (n - i - 1)গুলিয়ে ফেলা — শুরু বেছে নেওয়ার optioni + 1টা (index 0 থেকে i), শেষ বেছে নেওয়ার optionn - iটা (i থেকে n-1)। ছবি এঁকে নাও, মুখস্থ কোরো না। - 2D prefix-এ overlap দুবার বিয়োগ — formula-তে
+ P[r1-1][c1-1]ফেরত যোগ করতে ভুলে যাওয়া; inclusion-exclusion-এর কোণার ব্লকটা দুবার কাটা পড়ে, একবার ফেরত দিতে হয়। - Difference আর prefix-এর ক্রম গুলিয়ে ফেলা — সব update আগে শেষ করো, তারপর একবার prefix চালাও। মাঝপথে query এলে এই সরল কৌশল চলে না (তখন BIT/segment tree-র এলাকা)।
পরের level এ যাওয়ার আগে checklist¶
- [ ]
[2, 5, 1, 3]-এর prefix array হাতে বানিয়ে 2-3টা range query করেছি - [ ] একটা difference array-তে 3টা range update দিয়ে শেষে prefix চালিয়ে উত্তর মিলিয়েছি
- [ ] 073-এর hash map-এর dry run খাতায় করেছি — প্রতি step-এ map-এ কী আছে লিখে
- [ ]
(i + 1) * (n - i)-এর ছবি কাউকে বুঝিয়ে বলেছি (বাঁয়ে পছন্দ × ডানে পছন্দ) - [ ] 2D prefix-এর 4-term formula ছবি না দেখে একবার লিখেছি
- [ ] Imos method দিয়ে অন্তত একটা "অনেক মানুষ আসে-যায়" type উদাহরণ হাতে চালিয়েছি
সব টিক দিতে পারলে — চলো Level 6: Two Pointers ও Sliding Window-এ। সেখানে precompute নয় — দুটো আঙুল আর একটা জানালা দিয়ে array-র উপর হাঁটতে শিখবে।
Source map¶
এই folder-এর প্রতিটা concept আর problem কোথা থেকে এসেছে, কোন link official, আর কোনটা original লেখা — সব হিসাব আছে source-map.md-তে।