024 — Codeforces Blind Pick (Pattern Recognition)¶
Source¶
- Original source: Self-directed capstone — Codeforces থেকে চোখ-বুজে একটা 1400–1700 rated DP তুলে নাও
- Platform: Codeforces — https://codeforces.com/problemset/
- Topic: dynamic programming (pattern recognition across the whole folder)
- Difficulty: Hard
- Pattern: Pattern recognition (any family)
- Basic idea inherited from: পুরো folder — এটা কোনো নির্দিষ্ট problem নয়, একটা drill: code করার আগে শুধু title + constraints থেকে family-র নাম বলা
1. Problem in simple words¶
এটা একক problem নয়, একটা অভ্যাস। Codeforces problemset-এ যাও, "dp" tag দিয়ে filter করো, 1400–1700 rating-এ একটা problem না দেখে তুলে নাও। তারপর statement পড়ার আগে নয়, code লেখার আগে — শুধু title আর constraints থেকে বলো কোন DP family (1D / grid / knapsack / LIS / string / interval / DAG / bitmask)। এই note সেই ritual-টাকে একটা reusable checklist বানায়, আর একটা ছোট worked example দিয়ে দেখায় constraints থেকে কীভাবে family + complexity আন্দাজ করা যায়।
2. Which basic idea does this inherit from?¶
ভিত্তি গোটা folder — patterns.md-এর family-গুলো, state-transition-thinking.md-এর 5-step doctrine, আর আগের 23টা problem-এর muscle। আগের প্রতিটা note একটা নির্দিষ্ট family শিখিয়েছে; এই capstone সেগুলোকে এক জায়গায় এনে জিজ্ঞেস করে: "অদেখা একটা problem-এ তুমি কি trigger word থেকেই family চিনতে পারো?"
3. What is the hidden math or logic?¶
লুকানো logic constraint-পড়া। n-এর সীমাই target complexity ফাঁস করে দেয়, আর complexity প্রায়ই family-কে সংকীর্ণ করে:
n <= ~20 -> 2^n বা n*2^n সম্ভব -> bitmask DP
n <= ~500 -> O(n^2) বা O(n^3) ঠিক -> interval / two-string grid
n <= ~5000 -> O(n^2) ঠিক -> LIS(n^2) / knapsack
n <= ~10^5, 10^6 -> O(n) বা O(n log n) -> 1D linear / LIS(n log n)
দুটো sequence -> O(n*m) grid -> string DP
grid দেওয়া -> O(rows*cols) -> grid DP
"unlimited / coins" -> budget axis -> knapsack
এই mapping-টাই "hidden math": সংখ্যা → অনুমোদিত complexity → সম্ভাব্য family।
4. Which data structure is needed?¶
family-অনুযায়ী আলাদা — তাই কোনো একক উত্তর নেই, বরং একটা lookup:
1D linear -> dp[i] (array / দুই rolling variable)
grid -> dp[r][c] (2D array)
knapsack -> dp[budget] (1D, direction-সচেতন)
LIS -> dp[i] ends-at-i (array; n log n হলে tails + bisect)
string DP -> dp[i][j] (2D array)
interval -> dp[l][r] (2D, length-order fill)
DAG -> dp[v] (array + topo order)
bitmask -> dp[mask] (size-2^n array)
5. Why this data structure fits¶
প্রতিটা family-র state-আকার ঠিক ততটুকু তথ্য ধরে যতটা "শেষ decision" নিতে লাগে — এটাই doctrine-এর core। তাই data structure-টা state-আকারের সরাসরি অনুবাদ: prefix হলে 1D array, দুই sequence হলে 2D, subset মনে রাখা লাগলে bitmask। সঠিক family চিনলে data structure প্রায় নিজে নিজেই ঠিক হয়ে যায়।
6. Real-life analogy¶
ভাবো তুমি অভিজ্ঞ একজন ডাক্তার, আর রোগী (problem) ঘরে ঢুকল। তুমি পুরো ইতিহাস শোনার আগেই কয়েকটা লক্ষণ (trigger word, n-এর মান) দেখে সম্ভাব্য রোগের শ্রেণি (family) আন্দাজ করো — তারপর পরীক্ষা (5-step doctrine) করে নিশ্চিত হও। অভিজ্ঞতা মানে দ্রুত সঠিক shortlist বানানো, অন্ধ আন্দাজ নয়।
7. Visual explanation¶
একটা decision-tree হিসেবে family-spotting:
problem পড়ো
|
+-- দুটো string / sequence? ------------------> String DP dp[i][j]
|
+-- grid + "right/down"? ---------------------> Grid DP dp[r][c]
|
+-- "coins / items / capacity / budget"? -----> Knapsack dp[budget]
|
+-- "longest increasing / nesting / chain"? --> LIS dp[i]
|
+-- "merge/burst a range, neighbor cost"? ----> Interval dp[l][r]
|
+-- "prerequisites / DAG / longest chain"? ---> DP on DAG dp[v]
|
+-- n <= 20, "use each exactly once"? --------> Bitmask dp[mask]
|
+-- "n steps/days in a row, ways/best"? ------> 1D linear dp[i]
উপর থেকে নিচে প্রথম যেটা মেলে, সেটাই তোমার প্রথম সন্দেহ — তারপর doctrine দিয়ে যাচাই।
8. Example input and output¶
এই note-এর "input" হলো constraint, "output" হলো family-অনুমান:
"n <= 18, assign n tasks to n workers, min cost" -> bitmask DP, dp[mask]
"two strings up to 1000, min ops to make equal" -> string DP, dp[i][j]
"array up to 1e5, longest increasing subseq" -> LIS, dp[i] (n log n)
"coins unlimited, make amount A (A up to 1e6)" -> unbounded knapsack
"grid 1000x1000, min path cost top-left to bottom" -> grid DP, dp[r][c]
"merge n<=300 stones, cost = sum of merged" -> interval DP, dp[l][r]
9. Brute force thinking¶
প্রথম সরল চিন্তা (যেকোনো DP-র আগে): সব সম্ভাবনা enumerate করো — সব subset, সব permutation, বা সব path — আর best/count নাও। এটা প্রায় সবসময় exponential, কিন্তু এটাই সঠিক recurrence-এর কঙ্কাল দেয়: "শেষ decision কী, আর তার আগে কী জানা লাগত?"
10. Why brute force is slow¶
enumeration সাধারণত O(2^n), O(n!) বা branching recursion — overlapping subproblem-এর কারণে একই কাজ বারবার হয়। constraint যত বড়, brute তত দ্রুত অচল; আর constraint-এর আকারই বলে দেয় কত দ্রুত হতে হবে, তাই কোন family লাগবে।
11. Key observation¶
মূল observation: DP problem অসীম মনে হলেও বেশির ভাগই হাতে-গোনা কয়েকটা family-র সদস্য, আর constraint-এর সংখ্যা সেই family-কে আগেই সংকীর্ণ করে দেয়। তাই "এটা কোন DP?" আন্দাজ নয় — এটা trigger word + n-এর একটা lookup।
12. Optimized intuition¶
State (শব্দে): এই capstone-এ "state" হলো তোমার নিজের সিদ্ধান্ত-প্রক্রিয়ার state — কোন family shortlist করেছ আর কেন। কিন্তু drill-টা শক্ত করতে নিচের classify() function একটা concrete decision rule encode করে: feature (trigger word, constraint) → family-নাম।
Transition (decision rule):
family = first matching rule among:
has two sequences -> "string"
grid + right/down moves -> "grid"
coins/items + capacity -> "knapsack"
DAG / prerequisites -> "dag"
longest increasing/chain -> "lis"
merge/burst a range -> "interval"
n <= 20 + use-each-once -> "bitmask"
sequence + ways/best to i -> "1d-linear"
Base case: কোনো rule না মিললে → "needs a creative anchor or extra dimension" (LIS-এর শিক্ষা)।
Answer location: তোমার লেখা family-নাম, যেটা পরে 5-step doctrine দিয়ে যাচাই করবে।
13. Thinking tweak¶
মোচড়: unseen problem-এ সরাসরি code-এ ঝাঁপিয়ো না। আগে family guess লিখে রাখো, তারপর statement পড়ে guess যাচাই করো, তারপর 5 step কাগজে লেখো — তবেই editor। guess vs reality track করলে তোমার pattern-recognition দ্রুত নিজেকে শোধরায়; ভুল guess নিজেই সবচেয়ে দামি feedback।
14. Step-by-step dry run¶
একটা কাল্পনিক pick: "n ≤ 16 শহর, প্রতিটা ঠিক একবার ঘুরে min total distance":
- trigger: "n ≤ 16", "প্রতিটা একবার", "min cost" → subset মনে রাখা লাগবে
- constraint: n ≤ 16 → 2^16 ≈ 65536 affordable → bitmask সম্ভব
- family guess: bitmask DP,
dp[mask][last] - doctrine: state = "কোন শহর-set ভিজিট করা শেষ + এখন কোথায়"; transition = একটা unvisited শহর যোগ
- যাচাই: statement পড়ে নিশ্চিত — হ্যাঁ, classic TSP-ধাঁচ ✔
15. Python solution¶
# এই capstone-এর "solution" হলো একটা family-classifier:
# unseen problem-এর feature দিলে সম্ভাব্য DP family ফেরত দেয়।
# (একটা practice harness, সত্যিকারের solver নয় — কিন্তু runnable ও testable।)
def classify(features):
"""features: trigger word / constraint-এর একটা dict।"""
n = features.get("n", None)
text = " ".join(features.get("words", [])).lower()
if features.get("two_sequences"):
return "string"
if features.get("grid") and ("right" in text or "down" in text or "path" in text):
return "grid"
if ("coin" in text or "item" in text or "knapsack" in text
or features.get("capacity")):
return "knapsack"
if features.get("dag") or "prerequisite" in text or "dependency" in text:
return "dag"
if "increasing" in text or "nesting" in text or "chain" in text:
return "lis"
if "merge" in text or "burst" in text or "range" in text:
return "interval"
if n is not None and n <= 20 and ("each" in text or "every" in text
or "permutation" in text):
return "bitmask"
if "step" in text or "day" in text or "ways" in text or "house" in text:
return "1d-linear"
return "needs-anchor"
def target_complexity(n):
"""constraint -> অনুমোদিত complexity (পেন্সিল-rule)।"""
if n is None:
return "unknown"
if n <= 20:
return "O(2^n) / O(n*2^n)"
if n <= 500:
return "O(n^2) / O(n^3)"
if n <= 5000:
return "O(n^2)"
if n <= 10 ** 6:
return "O(n) / O(n log n)"
return "O(n) or better"
# ---- tests ----
fam_cases = [
({"two_sequences": True, "words": ["min ops to make equal"]}, "string"),
({"grid": True, "words": ["min path right down"]}, "grid"),
({"words": ["coins unlimited make amount"]}, "knapsack"),
({"words": ["longest increasing subsequence"]}, "lis"),
({"words": ["merge stones range cost"]}, "interval"),
({"words": ["course prerequisite longest chain"], "dag": True}, "dag"),
({"n": 16, "words": ["visit every city once permutation"]}, "bitmask"),
({"words": ["count ways to climb n steps"]}, "1d-linear"),
({"words": ["some weird novel thing"]}, "needs-anchor"),
]
for feat, want in fam_cases:
assert classify(feat) == want, (feat, classify(feat))
comp_cases = [
(16, "O(2^n) / O(n*2^n)"),
(300, "O(n^2) / O(n^3)"),
(5000, "O(n^2)"),
(100000, "O(n) / O(n log n)"),
(None, "unknown"),
]
for n, want in comp_cases:
assert target_complexity(n) == want, (n, target_complexity(n))
print("সব test pass!")
16. Line-by-line code explanation¶
classify: feature-dict (trigger word + constraint) নেয়; rule-গুলোpatterns.md-এর family-spotting table-এর order-এ প্রথম-মিল ভিত্তিতে family-নাম ফেরত দেয়; কিছু না মিললে"needs-anchor"।target_complexity:n-এর মান থেকে অনুমোদিত complexity-এর গুচ্ছ দেয় — ঠিক সেই পেন্সিল-নিয়ম যা contest-এ family সংকীর্ণ করতে কাজে লাগে।- দুই test block দেখায় classifier আর complexity-rule দুটোই প্রত্যাশিত family/complexity দেয়; এটা drill-এর mental model-কে concrete করে।
17. Output walkthrough¶
fam_cases-এ নয়টা feature-set: আট family-র একটা করে প্রতিনিধি (string, grid, knapsack, lis, interval, dag, bitmask, 1d-linear) আর একটা "novel" যেটা needs-anchor দেয়। comp_cases-এ পাঁচটা n-মান থেকে complexity। সব assert পাস হলে শেষে print: সব test pass!। (মনে রেখো: এটা একটা teaching harness — সত্যিকারের problem-এ এই rule-গুলো শুধু shortlist দেয়, doctrine-এর বদলি নয়।)
18. Time complexity¶
classify ও target_complexity দুটোই O(1) (constant কয়েকটা string-check)। মূল শিক্ষা অবশ্য picked problem-এর complexity আন্দাজ করা — যা family-অনুযায়ী O(n) থেকে O(n·2^n) পর্যন্ত।
19. Space complexity¶
harness-টা O(1) auxiliary। আসল DP-র space family-অনুযায়ী — 1D-তে O(n) (বা O(1)), grid/string-এ O(n·m), bitmask-এ O(2^n)।
20. Common mistakes¶
- statement পুরো না বুঝে family-তে commit করা — guess লেখো, কিন্তু doctrine দিয়ে যাচাই করো; trigger word মাঝে মাঝে বিভ্রান্ত করে।
- constraint উপেক্ষা করা — একই trigger word ছোট/বড় n-এ আলাদা family চায় (ছোট n হলে bitmask, বড় হলে greedy/অন্য কিছু)।
- কোনো family না মিললে হাল ছাড়া — সেটাই সংকেত যে state-এ একটা creative anchor বা extra dimension লাগবে (LIS-এর শিক্ষা)।
21. Which basic problem this inherits from¶
ভিত্তি: পুরো folder। ../patterns.md-এর family-spotting table আর ../state-transition-thinking.md-এর 5-step doctrine — এই দুটোই এই capstone-এর মেরুদণ্ড; classifier-টা ওই table-এরই code-রূপ।
22. Similar harder problems¶
- Codeforces-এর "dp" tag, rating 1700–2000 — https://codeforces.com/problemset/?tags=dp
- AtCoder Educational DP Contest (26টা ক্যানোনিকাল DP) — https://atcoder.jp/contests/dp
- USACO Guide Gold DP module — https://usaco.guide/gold/intro-dp
23. Pattern learned¶
Pattern recognition as a skill: problem পড়ো → trigger word + n দেখো → family shortlist করো → 5-step doctrine-এ যাচাই করো → তারপর code। guess vs reality track করলে recognition দ্রুত নিজেকে শোধরায়। "এটা কোন DP?" হয়ে যায় একটা দ্রুত lookup, অন্ধ আন্দাজ নয়।
24. Final summary¶
ভবিষ্যতের আমাকে: "DP capstone = চিনতে শেখা, solve করতে নয়।" Unseen problem-এ আগে family guess লেখো (trigger word + constraint থেকে), তারপর doctrine দিয়ে যাচাই করো, তারপর code। মনে রেখো: constraint-এর সংখ্যাই target complexity ফাঁস করে, আর complexity প্রায়ই family-কে সংকীর্ণ করে — এই reflex-ই পুরো folder-এর আসল পুরস্কার।
মনে রাখার নিয়ম (legal): সব নিজের ভাষায় লেখা; problem statement copy করা হয়নি; official link শুধু attribution-এর জন্য; "asked by Google/Amazon" দাবি নেই — এটা একটা common interview pattern।