এই পর্বে যা শিখবেন
- প্রোগ্রামিং কনটেস্ট কীভাবে চলে — সমস্যা, ইনপুট-আউটপুট, জাজ আর বাংলাদেশের কনটেস্টের জগৎ
- প্রতিটি verdict কী বলছে, আর সেটি দেখে পরের পদক্ষেপ কী হবে
- Constraints দেখে প্রয়োজনীয় গতি হিসাব করা ও সঠিক কৌশল বাছাই করা
- সবচেয়ে সাধারণ ফাঁদগুলো চেনা এবং stress testing দিয়ে লুকানো ভুল ধরা
- নিয়মিত উন্নতির একটি পদ্ধতি — upsolving, ভুলের খাতা, দলগত কৌশল আর AI-এর সঠিক ব্যবহার
১ · প্রোগ্রামিং কনটেস্ট আসলে কী
বোর্ড পরীক্ষার হলের কথা মনে করুন। নির্দিষ্ট সময়, কয়েকটি প্রশ্ন, আর খাতা জমা দেওয়ার পর একজন পরীক্ষক নম্বর দেন। প্রোগ্রামিং কনটেস্টও প্রায় তাই — শুধু পরীক্ষক একজন মানুষ নন, একটি প্রোগ্রাম। আর নম্বর আসে কয়েক মাস পরে নয়, কয়েক সেকেন্ডে।
Competitive programming-এ আপনাকে কয়েকটি সমস্যা দেওয়া হয়। প্রতিটির জন্য একটি প্রোগ্রাম লিখে জমা দিতে হয়। প্রোগ্রামটি stdin থেকে ইনপুট পড়বে, উত্তর লিখবে, এবং নির্দিষ্ট সময় ও মেমরির মধ্যে শেষ করবে। প্রতিটি সমস্যার বিবরণে সাধারণত পাঁচটি অংশ থাকে:
📜 গল্প ও কাজ
প্রায়ই একটি গল্পের মোড়কে — “রিকশাচালক রহিম সবচেয়ে কম দূরত্বে সব গলি ঘুরতে চায়।” গল্পের নিচে লুকানো থাকে আসল প্রশ্ন।
Problem statement📥 ইনপুট ও আউটপুটের ফরম্যাট
কোন লাইনে কী আসবে, উত্তর ঠিক কীভাবে ছাপতে হবে। একটি বাড়তি শব্দ বা ভুল জায়গায় নতুন লাইন দিলেও উত্তর ভুল ধরা হতে পারে।
Input / Output📏 সীমা
n সর্বোচ্চ কত, সংখ্যাগুলো কত বড়, সময় কত সেকেন্ড, মেমরি কত MB — এটিই সবচেয়ে গুরুত্বপূর্ণ অংশ। একে বলে constraints.
Constraints🧪 নমুনা
দু-একটি উদাহরণ ইনপুট ও সঠিক আউটপুট। নমুনা মিলে যাওয়া মানেই সমাধান ঠিক নয় — আসল পরীক্ষা হয় গোপন টেস্টে।
Sample testsজমা দেওয়ার পর জাজ আপনার কোড compile করে, তারপর আগে থেকে তৈরি করা কয়েক ডজন বা কয়েকশো গোপন test case-এ চালায়। প্রতিটির আউটপুট সঠিক উত্তরের সাথে মেলায়। সব মিললে আপনি পান সবুজ সংকেত। একটি না মিললেই লাল।
বাংলাদেশ ও বিশ্বের কনটেস্টের জগৎ
বিশ্ববিদ্যালয়ের ছাত্রছাত্রীদের সবচেয়ে বড় মঞ্চ হলো ICPC. তিনজনের একটি দল, একটি কম্পিউটার, পাঁচ ঘণ্টা আর দশটির মতো সমস্যা — এটাই এর চিরচেনা রূপ। প্রথমে আঞ্চলিক পর্ব (regional), সেখান থেকে বাছাই করা দলগুলো যায় World Finals-এ। ঢাকায় বহু বছর ধরে ICPC-র একটি এশীয় আঞ্চলিক পর্ব আয়োজিত হয়ে আসছে, আর বাংলাদেশের বিশ্ববিদ্যালয়ের দলগুলো প্রায় নিয়মিতভাবেই World Finals-এ অংশ নেয়।
দেশের ভেতরে আছে জাতীয় পর্যায়ের NCPC (National Collegiate Programming Contest) আর বিভিন্ন বিশ্ববিদ্যালয়ের আয়োজনে হয় IUPC (Inter University Programming Contest) নামের আন্তঃবিশ্ববিদ্যালয় কনটেস্ট। স্কুল-কলেজের শিক্ষার্থীদের জন্য আছে ইনফরমেটিক্স অলিম্পিয়াড, যেখান থেকে আন্তর্জাতিক অলিম্পিয়াড IOI-এর দল বাছাই হয়।
| প্ল্যাটফর্ম | বৈশিষ্ট্য | কার জন্য ভালো |
|---|---|---|
| Codeforces | প্রায় প্রতি সপ্তাহে কয়েক ঘণ্টার কনটেস্ট, প্রতিটি অংশগ্রহণে rating বাড়ে-কমে, পরে editorial প্রকাশ হয় | নিয়মিত প্রতিযোগিতার অভ্যাস |
| AtCoder | জাপানের প্ল্যাটফর্ম; পরিষ্কার ভাষায় লেখা, ধাপে ধাপে কঠিন হওয়া সমস্যা | নতুনদের ভিত্তি মজবুত করা |
| LightOJ | বাংলাদেশি প্রোগ্রামারের তৈরি; বিষয় ধরে সাজানো সমস্যার সংগ্রহ | একটি বিষয় ধরে গভীর অনুশীলন |
| Toph | বাংলাদেশে তৈরি; দেশের অনেক বিশ্ববিদ্যালয়ের কনটেস্ট এখানে হয় | দেশীয় কনটেস্টে অংশ নেওয়া |
| UVa, Kattis | বহু পুরোনো, বিশাল সমস্যার সংগ্রহশালা; অনেক পুরোনো ICPC সমস্যাও আছে | ক্লাসিক সমস্যা চর্চা |
ICPC-র শুরু ১৯৭০-এর দশকে, যুক্তরাষ্ট্রের বিশ্ববিদ্যালয়গুলোর মধ্যে একটি ছোট প্রতিযোগিতা হিসেবে। আজ এতে শতাধিক দেশের বিশ্ববিদ্যালয় অংশ নেয়। বাংলাদেশে এই সংস্কৃতি গড়ে উঠেছে বহু শিক্ষক, কোচ আর প্রাক্তন প্রতিযোগীর স্বেচ্ছাশ্রমে।
কনটেস্টে আপনার সমাধানকে তিনটি পরীক্ষায় পাস করতে হয় — সঠিক (প্রতিটি গোপন টেস্টে), দ্রুত (সময়সীমার মধ্যে), আর সাশ্রয়ী (মেমরির সীমার মধ্যে)। নতুনরা প্রথমটি নিয়ে ভাবেন, অভিজ্ঞরা লেখা শুরুর আগেই তিনটি নিয়ে ভাবেন।
২ · Verdict — জাজের ছোট রায়ে বড় তথ্য
জাজ আপনাকে কখনো বলে না ভুলটা কোথায়। সে শুধু একটি ছোট verdict দেয় — দুই-তিন অক্ষরের একটি রায়। ডাক্তারের রিপোর্টের মতো ভাবুন: “জ্বর আছে” শুনে আপনি জানেন না রোগটা কী, কিন্তু কোন দিকে খুঁজতে হবে তা বুঝে যান। প্রতিটি verdict-ও তেমনি খোঁজার দিক দেখিয়ে দেয়।
| Verdict | যা ঘটেছে | প্রথমে যা খুঁজবেন |
|---|---|---|
| ✅ AC — Accepted | সব টেস্টে সঠিক, সময় ও মেমরির ভেতরে | পরের সমস্যায় যান; পরে দেখুন আরও সহজ সমাধান ছিল কি না |
| ❌ WA — Wrong Answer | কোনো টেস্টে আউটপুট মেলেনি | Overflow, edge case (n = 1, সব সমান, ঋণাত্মক), reset ভুলে যাওয়া, আউটপুটের ফরম্যাট |
| ⏱️ TLE — Time Limit Exceeded | সময়সীমা পেরিয়ে গেছে | অ্যালগরিদমের গতি constraints-এর তুলনায় কম; অসীম লুপ; খুব বড় ইনপুটে ধীর পড়া |
| 💾 MLE — Memory Limit Exceeded | মেমরির সীমা পেরিয়েছে | অপ্রয়োজনে বিশাল array, n × n টেবিল, ছাড়া না হওয়া মেমরি |
| 💥 RE — Runtime Error | চলতে চলতে crash | Array-র সীমার বাইরে যাওয়া, শূন্য দিয়ে ভাগ, গভীর রিকার্শন বা বড় লোকাল array-তে stack ফুরিয়ে যাওয়া |
| 🛠️ CE — Compilation Error | জাজ compile করতেই পারেনি | ভুল ভাষা বা compiler বাছাই, বাদ পড়া header, শুধু Windows-এ চলে এমন header (conio.h) |
একটি সূক্ষ্ম কথা খেয়াল করুন। অনেক জাজ verdict-এর সাথে বলে দেয় কোন টেস্টে আটকেছে — যেমন “Wrong answer on test 7”. প্রথম কয়েকটি টেস্ট সাধারণত নমুনা। তাই test 1-এ WA মানে নমুনাতেই ভুল — জমা দেওয়ার আগে নিজে চালিয়ে দেখেননি। আর অনেক পরের টেস্টে WA প্রায়ই বড় সংখ্যার overflow বা কোনো বিরল edge case-এর দিকে ইঙ্গিত করে।
কিছু জাজে WA আর TLE একসাথে লুকিয়ে থাকে। জাজ সাধারণত প্রথম ব্যর্থ টেস্টেই থেমে যায়, তাই TLE সারানোর পর পরের টেস্টে WA আসতেই পারে। হতাশ হবেন না — এটি অগ্রগতির লক্ষণ।
ICPC-ধাঁচের কনটেস্টে প্রতিটি ভুল জমার জন্য সময়ের শাস্তি (penalty) যোগ হয় — সাধারণত ২০ মিনিট, যদি সমস্যাটি শেষ পর্যন্ত সমাধান হয়। তাই জমার আগে অন্তত নমুনা আর দু-একটি নিজের বানানো edge case চালিয়ে নিন।
৩ · Constraints পড়ে অ্যালগরিদম বাছাই
কনটেস্টের সবচেয়ে শক্তিশালী কৌশলটি অনেকেই জানেন না: constraints আপনাকে সমাধানের ইঙ্গিত দিয়ে দেয়। সমস্যা-লেখক জানেন কোন গতির সমাধান তিনি চান। সেই অনুযায়ী তিনি n-এর সীমা বেঁধে দেন। আপনি উল্টো দিক থেকে হিসাব করলেই বুঝবেন কোন ধরনের অ্যালগরিদম খুঁজতে হবে।
হিসাবের ভিত্তি একটি মোটা দাগের নিয়ম: সাধারণ একটি জাজ-কম্পিউটার এক সেকেন্ডে মোটামুটি ১০৮টি সহজ কাজ (যোগ, তুলনা, array থেকে পড়া) করতে পারে। এটি নিখুঁত নয় — কাজের ধরন, cache আর compiler-এর ওপর নির্ভর করে কয়েক গুণ কম-বেশি হয়। কিন্তু অনুমানের জন্য যথেষ্ট। পর্ব ৩৯-এ শেখা time complexity-র এখানেই আসল ব্যবহার।
| n-এর সীমা | যে গতি চলবে | সাধারণত যে কৌশল |
|---|---|---|
| n ≤ ১০–১২ | O(n!) বা O(n · 2n) | সব বিন্যাস বা সব উপসেট যাচাই, backtracking |
| n ≤ ২০ | O(2n) বা O(2n · n) | উপসেট ধরে খোঁজা, bitmask দিয়ে DP |
| n ≤ ৫০০ | O(n3) | তিন স্তরের লুপ, ছোট গ্রাফে সব জোড়ার দূরত্ব |
| n ≤ ৫০০০ | O(n2) | দুই স্তরের লুপ, দুই মাত্রার DP |
| n ≤ ১০৫ থেকে ১০৬ | O(n log n) বা O(n) | সর্টিং, binary search, prefix sum, BFS/DFS |
| n ≤ ১০৯ থেকে ১০১৮ | O(log n) বা O(1) | সূত্র, উত্তরের ওপর binary search, দ্রুত ঘাত (fast power) |
টেবিলটি মুখস্থ করার জিনিস নয় — নিজেই বের করা যায়। n = ১০৫ হলে n2 = ১০১০, অর্থাৎ প্রায় ১০০ সেকেন্ড। সময়সীমা ১ সেকেন্ড হলে তা নিশ্চিত TLE. অথচ n log n হলে মাত্র ১৭ লাখের মতো কাজ — চোখের পলকে শেষ। নিচের ডায়াগ্রামে একটি আসল সমস্যায় এই হিসাবটি ধাপে ধাপে দেখুন:
- পড়া
n, q ≤ 2e5সীমা খুঁজুন - সহজ পথ
n × qখরচ কত? - বাজেট
~1e8 / sকত দ্রুত লাগবে - ছাঁচ
sort + bsearchচেনা কৌশল - পরিকল্পনা
(n+q) log nলেখা শুরু
একটি দোকানে n টি জিনিস, প্রতিটির দাম দেওয়া আছে। q জন ক্রেতা আসবে; প্রত্যেকের কাছে x টাকা। প্রত্যেকের জন্য বলুন: কয়টি জিনিসের দাম x বা তার কম? Constraints: 1 <= n, q <= 200000; 1 <= price, x <= 10^9 Time limit: 1 second
for each query x: /* q বার */ count = 0 for each price p: /* n বার */ if p <= x: count++ মোট কাজ = n × q = 2e5 × 2e5 = 4e10
4e10 / 1e8 = প্রায় 400 সেকেন্ড → TLE নিশ্চিত লক্ষ্য: মোট কাজ 1e7-এর কাছাকাছি বা কম n log n = 2e5 × 18 ≈ 3.6e6 → আরামে চলবে
১. দামগুলো একবার সাজান O(n log n) — পর্ব ৪০ ২. প্রতিটি x-এর জন্য binary search: x-এর চেয়ে বড় প্রথম দাম কোথায়? O(log n) — পর্ব ৪১ সেই অবস্থানই হলো উত্তর মোট = (n + q) × log n ≈ 7e6
দাম ও x <= 1e9 → int-এ ধরে (int-এর সীমা প্রায় 2.1e9)
উত্তর <= n = 2e5 → int যথেষ্ট
ইনপুট ≈ 4e5 সংখ্যা → scanf যথেষ্ট দ্রুত
array: 2e5 × 4 byte = 0.8 MB → global রাখুন
পরিকল্পনা তৈরি — এবার কোড লেখার পালা
- প্রথমে সীমা খুঁজুন। গল্পটা পড়ার পর চোখ যাবে constraints-এ: n আর q দুটোই ২ লাখ পর্যন্ত, দাম ১০০ কোটি পর্যন্ত, সময় ১ সেকেন্ড। এই তিনটি সংখ্যাই পরের সব সিদ্ধান্ত নেবে।
- সবচেয়ে সহজ সমাধানের খরচ হিসাব করুন। প্রতিটি ক্রেতার জন্য সব দাম গুনলে কাজ হয় n × q = ৪ × ১০১০. কোড লেখার আগেই এই গুণটি করে ফেলুন।
- বাজেটের সাথে মেলান। এক সেকেন্ডে প্রায় ১০৮ কাজ ধরলে সহজ পথে লাগবে ৪০০ সেকেন্ড — নিশ্চিত TLE. অর্থাৎ দরকার n log n ধরনের কিছু।
- চেনা ছাঁচ খুঁজুন। “তালিকা বদলায় না, কিন্তু প্রশ্ন অনেক” — এই ধরনটি দেখলেই মাথায় আসা উচিত: একবার সাজিয়ে নিন, তারপর প্রতিটি প্রশ্নে binary search.
- লেখার আগে শেষ যাচাই। সংখ্যাগুলো
int-এ ধরবে কি না, ইনপুট কত বড়, array কোথায় রাখবেন — এক মিনিটের এই যাচাই পরে আধা ঘণ্টার debugging বাঁচায়।
৪ · সমস্যার ভেতরের চেনা ছাঁচ
অভিজ্ঞরা প্রতিটি সমস্যা শূন্য থেকে ভাবেন না; খোঁজেন — “এই সমস্যাটি আমার চেনা কোন সমস্যার ছদ্মবেশ?” পর্ব ০২-এ শেখা pattern recognition-এর এটাই সবচেয়ে কাজের রূপ। দাবা খেলোয়াড় যেমন হাজারো অবস্থান দেখে এক নজরে চাল বোঝেন, প্রোগ্রামারও শত শত সমস্যা সমাধান করে ছাঁচ চিনতে শেখেন।
গত কয়েকটি পর্বে আপনি যে কৌশলগুলো শিখেছেন, সেগুলোকে চেনার কিছু সংকেত নিচে দেওয়া হলো:
| সমস্যায় যে সংকেত দেখবেন | সম্ভাব্য কৌশল | কোথায় শিখেছেন |
|---|---|---|
| “সাজানো অবস্থায় থাকলে সহজ হতো”, জোড়া খোঁজা, সবচেয়ে কাছের মান | সর্টিং, তারপর দুই পয়েন্টার বা binary search | পর্ব ৪০, ৪১ |
| “সর্বনিম্ন কত হলে সম্ভব?” আর উত্তর বাড়লে সম্ভাবনা একদিকেই বদলায় | উত্তরের ওপর binary search | পর্ব ৪১ |
| “কত উপায়ে?”, “সর্বোচ্চ লাভ”, ছোট সমস্যার উত্তর বারবার লাগে | Dynamic programming | পর্ব ৪২ |
| প্রতি ধাপে “এখনকার সেরা” বেছে নিলেই শেষ পর্যন্ত সেরা হয় বলে মনে হয় | Greedy — তবে প্রমাণ বা অন্তত stress test জরুরি | পর্ব ৪৩ |
| শহর ও রাস্তা, বন্ধুত্ব, গ্রিডে চলাফেরা, “সবচেয়ে কম ধাপে” | Graph, BFS/DFS, shortest path | পর্ব ৩৮ |
| ভাগশেষ, গুণনীয়ক, মৌলিক সংখ্যা, “উত্তর 10^9 + 7 দিয়ে ভাগশেষ” | নাম্বার থিওরি, ভাগশেষের হিসাব | পর্ব ৪৩ |
| দ্রুত খোঁজা “এটি আগে এসেছে কি না”, গণনা | Hash table বা সর্টিং | পর্ব ৩৭ |
যখন কোনো ছাঁচই মেলে না, তখন তিনটি কাজ প্রায় সবসময় সাহায্য করে: (১) খুব ছোট n-এর জন্য হাতে উত্তর বের করুন, (২) সেই উত্তরগুলো পাশাপাশি লিখে কোনো নিয়ম চোখে পড়ে কি না দেখুন, (৩) সমস্যাটিকে সহজ করুন — “যদি সব সংখ্যা ধনাত্মক হতো?”, “যদি শুধু একটি প্রশ্ন থাকত?” সহজ রূপের সমাধান থেকে প্রায়ই আসল সমাধানের পথ বেরিয়ে আসে।
৫ · যে ফাঁদে সবাই অন্তত একবার পড়ে
কনটেস্টে বেশিরভাগ WA আসে কঠিন অ্যালগরিদমের ভুল থেকে নয় — আসে ছোট, প্রায় হাস্যকর ভুল থেকে। ভালো খবর হলো, এই তালিকা ছোট।
🔢 Integer overflow
int-এর সীমা প্রায় ২১৪ কোটি। দুটি ১০৯ গুণ করলে হয় ১০১৮ — int-এ ধরে না, তবে long long-এ (সীমা প্রায় ৯ × ১০১৮) ধরে। দুটি int গুণ করে long long-এ রাখলেও লাভ নেই — গুণটাই আগে int-এ হয়ে overflow করে। লিখুন (long long)a * b.
🔁 Reset ভুলে যাওয়া
এক ইনপুটে অনেকগুলো test case থাকলে প্রতিটির শুরুতে যোগফল, গণনা, visited array — সব আবার শূন্য করতে হয়। নমুনায় প্রায়ই একটিই test case থাকে, তাই এই ভুল নমুনায় ধরা পড়ে না।
নিচের ডায়াগ্রাম🧱 বড় লোকাল array
main-এর ভেতরে int a[1000000]; মানে stack-এ প্রায় ৪ MB. অনেক সিস্টেমে stack এর চেয়ে ছোট, ফলে stack overflow আর RE. বড় array ফাংশনের বাইরে global বা static করে রাখুন।
📐 Off-by-one
সমস্যা গোনে ১ থেকে n, আপনার array গোনে ০ থেকে n − ১. সীমায় < না <=? এই দোটানাই off-by-one ভুলের জন্ম দেয়। নিরাপদ থাকতে array এক ঘর বড় করে নেওয়া অনেকের অভ্যাস।
🖨️ আউটপুটের ফরম্যাট
সমস্যা চাইছে Case 1: 6, আপনি ছাপলেন Case 1:6 বা case 1: 6. যন্ত্র এগুলোকে আলাদা উত্তর ধরতে পারে। “Enter a number:” ধরনের বাড়তি লেখা কখনো ছাপবেন না — জাজ সেটিকেও আউটপুট ধরে।
📭 ইনপুট শেষ পর্যন্ত পড়া
কিছু সমস্যা বলে না কয়টি test case আছে — “ফাইল শেষ না হওয়া পর্যন্ত পড়ুন।” তখন লিখুন while (scanf("%lld", &x) == 1); scanf ফাইলের শেষে (EOF) পৌঁছালে 1 ফেরত দেয় না, লুপ থেমে যায়।
long long ছাপতে বা পড়তে %lld লাগে; ভুল format specifier দিলে প্রায়ই অদ্ভুত সংখ্যা আসে। -Wall চালু রাখলে compiler নিজেই এই ভুলের warning দেয়।
এবার সবচেয়ে চতুর ফাঁদটি ধাপে ধাপে দেখুন। প্রোগ্রামটি প্রতিটি test case-এর সংখ্যাগুলোর যোগফল ছাপে। ইনপুটে দুটি test case থাকবে: প্রথমটিতে 1 2 3, যার উত্তর 6, আর দ্বিতীয়টিতে 10 20, যার উত্তর হওয়া উচিত ৩০। প্রথম test case ঠিকঠাক চলবে — দেখুন দ্বিতীয়টিতে কী হয়।
1#include <stdio.h>2long long sum = 0; /* outside the loop! */3int main(void) {4 int t, n, x;5 scanf("%d", &t);6 while (t--) {7 scanf("%d", &n);8 for (int i = 0; i < n; i++) {9 scanf("%d", &x); sum += x;10 }11 printf("%lld\n", sum);12 }13}
| t | |
| n | |
| sum |
- শুরু। লাইন ২-এ
sumতৈরি হলো, মান 0. এটি লুপের বাইরে, তাই মাত্র একবারই শূন্য হবে। - প্রথম লাইন থেকে পড়া হলো
t= 2, অর্থাৎ দুটি test case আসছে। - Test case ১ শুরু।
while (t--)যাচাই করল 2 (সত্য), তারপর t কমে হলো 1. পড়া হলো n = 3. - লুপ তিনটি সংখ্যা পড়ল — 1, 2, 3.
sum= 0 + 1 + 2 + 3 = 6. - ছাপা হলো 6 — সঠিক। নমুনায় শুধু এই test case থাকলে আপনি নিশ্চিন্তে জমা দিতেন।
- Test case ২ শুরু। t কমে 0, পড়া হলো n = 2. কিন্তু দেখুন —
sumএখনো 6! আগের হিসাব মুছে যায়নি। - লুপ পড়ল 10 আর 20.
sum= 6 + 10 + 20 = 36. সঠিক উত্তর হওয়ার কথা 30. - ছাপা হলো 36 — জাজ বলবে Wrong Answer.
- সমাধান।
long long sum = 0;লাইনটিwhile-এর ভেতরে, n পড়ার ঠিক পরে নিয়ে আসুন। এখন আউটপুট আসে 6 ও 30. নিয়মটি মনে রাখুন: একটি test case-এর সব অবস্থা সেই test case-এর ভেতরেই তৈরি করুন।
এই শিক্ষাগুলো একসাথে করে একটি নির্ভরযোগ্য কাঠামো বানানো যায়, যা প্রায় প্রতিটি multi-test সমস্যায় কাজে লাগে। নিচের প্রোগ্রামটি প্রথমে T পড়ে, তারপর প্রতিটি test case-এ n টি সংখ্যা পড়ে যোগফল ও সর্বোচ্চ মান ছাপে। ইনপুটে ইচ্ছা করে তিনটি ১০৯ রাখা হয়েছে, যাদের যোগফল int-এ ধরত না:
#include <stdio.h>
int main(void) {
int t, n;
long long x;
if (scanf("%d", &t) != 1) return 1;
for (int tc = 1; tc <= t; tc++) {
if (scanf("%d", &n) != 1) return 1;
long long sum = 0, mx = 0; /* reset for EVERY test case */
for (int i = 0; i < n; i++) {
if (scanf("%lld", &x) != 1) return 1;
sum += x;
if (i == 0 || x > mx) mx = x; /* first value starts the max */
}
printf("Case %d: sum=%lld max=%lld\n", tc, sum, mx);
}
return 0;
}তিনটি অভ্যাস খেয়াল করুন। এক, sum আর mx তৈরি হয়েছে test case-এর লুপের ভেতরে — reset ভুলে যাওয়ার সুযোগই নেই। দুই, যোগফল long long, ছাপা হয়েছে %lld দিয়ে — তাই প্রথম কেসে 3000000000 ঠিকঠাক আসে। তিন, সর্বোচ্চ মান শুরু হয়েছে প্রথম সংখ্যা দিয়ে (i == 0), শূন্য দিয়ে নয়। কোনো কেসে সব সংখ্যা ঋণাত্মক হলে mx = 0 দিয়ে শুরু করা ভুল উত্তর দিত। ইনপুট বদলে 3 / -4 -2 -9 দিয়ে নিজে পরীক্ষা করুন।
৬ · Fast I/O — যখন ইনপুট পড়াই ধীর
কখনো কখনো অ্যালগরিদম ঠিক থাকলেও TLE আসে, কারণ ইনপুট পড়তেই সময় শেষ। প্রতিটি সংখ্যা পড়তে scanf format string বিশ্লেষণ করে, তারপর অক্ষর থেকে সংখ্যা বানায় — এক-একবারে খরচ সামান্য, কিন্তু ১০ লাখ বারে টের পাওয়া যায়।
প্রথম কথা: বেশিরভাগ সমস্যায় scanf আর printf যথেষ্ট দ্রুত। সমস্যা হয় শুধু ইনপুট সত্যিই বিশাল হলে, অথবা নিজের অজান্তে আউটপুট ধীর করে ফেললে। তখনই কাজে আসে fast I/O কৌশল।
getchar একটি করে অক্ষর পড়ে, আর C-র standard library ভেতরে বড় বড় টুকরোয় ইনপুট এনে রাখে — একে বলে buffering. তাই নিজে অক্ষর জুড়ে সংখ্যা বানালে format string বিশ্লেষণের খরচ বাঁচে। এটি চালানোর জন্য নয়, চিনে রাখার জন্য:
static long long read_ll(void) {
int c = getchar(), neg = 0;
long long x = 0;
while (c != EOF && c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') { neg = 1; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + (c - '0'); c = getchar(); }
return neg ? -x : x;
}প্রথম লুপ ফাঁকা জায়গা ও নতুন লাইন পেরিয়ে যায়, দ্বিতীয় লুপ অঙ্কগুলো জুড়ে সংখ্যা বানায়: “472” → 4 → 47 → 472.
আউটপুটও buffer-এ জমে, তারপর একসাথে লেখা হয়। কিন্তু প্রতিটি লাইনের পর fflush(stdout) ডাকলে প্রতিবার আলাদা করে অপারেটিং সিস্টেমের কাছে যেতে হয় — ১০ লাখ লাইনে সেটি খুব ধীর। কনটেস্টে সাধারণ সমস্যায় flush করার দরকার নেই; প্রোগ্রাম শেষ হলে C নিজেই বাকি লেখা পাঠিয়ে দেয়।
ব্যতিক্রম একটিই: interactive সমস্যা, যেখানে জাজ আপনার প্রতিটি প্রশ্নের উত্তর দেয়। সেখানে প্রতিটি প্রশ্ন ছাপার পর flush করতেই হবে, নইলে জাজ প্রশ্নটি দেখতেই পাবে না।
Fast I/O হলো শেষ ধাপের পালিশ, মূল সমাধান নয়। n2 থেকে n log n-এ যাওয়া মানে হাজার গুণ দ্রুত হওয়া; I/O বদলে বড়জোর কয়েক গুণ। আগে বড় লাভটি নিন।
৭ · Stress testing — চোখে না খুঁজে যন্ত্র দিয়ে ভুল খোঁজা
WA পেলেন, নমুনা মিলছে, কোড দশবার পড়লেন — ভুল চোখে পড়ছে না। এখানে অভিজ্ঞরা যে কৌশল ব্যবহার করেন, তার নাম stress testing.
ভাবনাটি সহজ। তিনটি জিনিস লাগে:
- একটি brute force সমাধান — ধীর, কিন্তু এত সরল যে ভুল হওয়ার সুযোগ প্রায় নেই। যেমন সব জোড়া পরীক্ষা করা।
- আপনার দ্রুত সমাধান — যেটি জমা দিয়েছিলেন এবং যেটিতে কোথাও ভুল লুকিয়ে আছে।
- একটি এলোমেলো ইনপুট তৈরির প্রোগ্রাম — ছোট ছোট, নানা রকম ইনপুট বানায়।
তারপর একটি লুপ: ইনপুট বানানো, দুই সমাধানে চালানো, উত্তর মেলানো — হাজার বার। উত্তর না মিললেই থেমে সেই ছোট ইনপুটটি দেখানো। তার debugging অনেক সহজ।
একটি বাস্তব ধাঁচের গল্প দিয়ে পুরো যাত্রাটি দেখুন। সমস্যা: n টি সংখ্যা (প্রতিটি ১০৯ পর্যন্ত) আর q টি প্রশ্ন; প্রতিটি প্রশ্নে l থেকে r পর্যন্ত সংখ্যাগুলোর যোগফল বলতে হবে।
- WA
test 9জাজের রায় - কোড পড়া
20 minকিছু পাওয়া গেল না - Brute
loop l..rসরল সমাধান - এলোমেলো টেস্ট
genমেলানো - অমিল
overflowভুল ধরা পড়ল - AC
long longসংশোধন
Test 1 ... passed
Test 2 ... passed
...
Wrong answer on test 9
int pre[200001]; /* pre[i] = a[1] + ... + a[i] */ ... pre[i] = pre[i - 1] + a[i]; ... printf("%d\n", pre[r] - pre[l - 1]); যুক্তি ঠিক আছে, নমুনাও মিলছে…
for each query (l, r):
long long s = 0;
for (i = l; i <= r; i++) s += a[i];
printf("%lld\n", s);
O(n × q) — জমা দিলে TLE, কিন্তু উত্তর নিশ্চিত সঠিক
test 1 ... same test 2 ... same ... test 1000 ... same সব মিলছে! তাহলে ভুলটা ছোট সংখ্যায় নেই। → constraints আবার পড়ি: মান 10^9 পর্যন্ত…
Mismatch on test 3
input: n=3 a = 1000000000 1000000000 1000000000
query: l=1 r=3
brute: 3000000000
fast: -1294967296
long long pre[200001]; ... printf("%lld\n", pre[r] - pre[l - 1]); Accepted
- WA on test 9. নমুনা মিলেছিল, তবু ৯ নম্বর টেস্টে ভুল। প্রথম কয়েকটি টেস্ট পেরিয়ে গেছে — অর্থাৎ মূল যুক্তি সম্ভবত ঠিক, সমস্যা কোনো বিশেষ ধরনের ইনপুটে।
- কোড পড়ে কিছু পাওয়া গেল না। Prefix sum-এর যুক্তি ঠিক, সূচকও ঠিক। বিশ মিনিট চলে গেল। বেশিরভাগ মানুষ এখানেই আটকে থাকেন।
- পাঁচ মিনিটে একটি brute force. প্রতিটি প্রশ্নে সরাসরি l থেকে r যোগ। জমা দিলে TLE হবে, কিন্তু এটি একটি “নিশ্চিত সঠিক” উত্তরদাতা, যার সাথে মেলানো যায়।
- ছোট এলোমেলো ইনপুটে মেলানো। ১ থেকে ১০-এর মধ্যে মান দিয়ে হাজারটি টেস্ট — সব মিলে গেল। অর্থাৎ ভুলটা যুক্তিতে নয়। Constraints আবার পড়তেই চোখে পড়ল — মান ১০৯ পর্যন্ত।
- বড় মানে অমিল! মাত্র তিনটি ১০৯-এর যোগফল ৩০০ কোটি, কিন্তু
intধরে প্রায় ২১৪ কোটি পর্যন্ত। ফলে মান ঘুরে ঋণাত্মক হয়ে গেছে (wraparound; C-র নিয়মে signed overflow আসলে অনির্ধারিত আচরণ)। - সংশোধন ও AC.
pre-কেlong longকরা হলো, ছাপা হলো%lldদিয়ে। আবার stress test, তারপর জমা — Accepted. শিক্ষা: এলোমেলো ইনপুটের মানের পরিসর constraints-এর পুরো সীমা পর্যন্ত ছড়িয়ে দিতে হবে, শুধু ছোট মানে নয়।
এবার সেই লুপটির ভেতরটা দেখুন। কনটেস্টে সাধারণত তিনটি আলাদা প্রোগ্রাম (gen, brute, fast) বানিয়ে একটি ছোট shell script দিয়ে চালানো হয়। প্রতিটি ধাপে কোন লাইন চলছে আর ফাইলগুলোতে কী আছে, খেয়াল করুন:
1for i in $(seq 1 1000); do2 ./gen $i > in.txt3 ./brute < in.txt > b.txt4 ./fast < in.txt > f.txt5 if ! cmp -s b.txt f.txt; then6 echo "Mismatch on $i"; cat in.txt; break7 fi8done
| i | |
| in.txt | |
| b.txt | |
| f.txt |
- লুপ শুরু, i = 1. সমস্যাটি: কয়েকটি সংখ্যা থেকে দুটি আলাদা সংখ্যা বেছে সর্বোচ্চ গুণফল। আমরা ১০০০ বার চেষ্টা করব।
i-কে seed হিসেবে gen-কে দেওয়া হবে, যাতে প্রতিবার ভিন্ন ইনপুট আসে। - Gen ইনপুট বানাল।
./gen 1তিনটি এলোমেলো অঙ্ক লিখলin.txt-এ: 4, 1, 7. ছোট ইনপুট ইচ্ছাকৃত। - দুই সমাধান চলল। Brute সব জোড়া দেখে বলল 4 × 7 = 28. Fast (সবচেয়ে বড় দুটি খুঁজে গুণ) বলল 28.
- তুলনা: মিল।
cmp -sদুই ফাইল হুবহু এক পেয়েছে, তাইif-এর ভেতরে ঢুকল না। লুপ পরের দফায় যাচ্ছে। - i = 2, নতুন ইনপুট। এবার 2, 8, 5 — ফাইলটি নতুন করে লেখা হলো।
- Brute: 8 × 5 = 40. Fast: 40. আবার মিল। বাস্তবে শত শত দফা এভাবে চলে যেতে পারে।
- i = 3: ইনপুট 9, 1, 4. Brute সঠিকভাবে বলল 9 × 4 = 36. কিন্তু fast বলল 81 — অর্থাৎ 9 × 9! সবচেয়ে বড় সংখ্যাটি প্রথম ঘরে থাকলে fast সমাধান একই সংখ্যাকে দুবার নিচ্ছে।
- অমিল ধরা পড়ল, লুপ থামল। স্ক্রিপ্ট ইনপুটটি ছেপে দিল। এখন আপনার হাতে তিন সংখ্যার একটি ইনপুট, যেটিতে ভুল নিশ্চিতভাবে ঘটে — কাগজ-কলমে এক মিনিটের কাজ।
shell script ছাড়াও পুরো ব্যাপারটি একটি প্রোগ্রামের ভেতরেই করা যায়। নিচের প্রোগ্রামে brute, fast আর এলোমেলো ইনপুট — তিনটিই একসাথে। Fast ফাংশনে উপরের ভুলটিই রাখা আছে। চালিয়ে দেখুন stress test কত দ্রুত সেটি ধরে:
#include <stdio.h>
#include <stdlib.h>
int brute(const int *a, int n) { /* every pair: O(n^2), surely right */
int best = 0;
for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++)
if (a[i] * a[j] > best) best = a[i] * a[j];
return best;
}
int fast(const int *a, int n) { /* two largest: O(n), has a bug */
int i1 = 0, i2 = 0;
for (int i = 1; i < n; i++) if (a[i] > a[i1]) i1 = i;
for (int i = 0; i < n; i++) if (i != i1 && a[i] > a[i2]) i2 = i;
return a[i1] * a[i2];
}
int main(void) {
int a[3], t;
srand(42); /* fixed seed: same tests every run */
for (t = 1; t <= 1000; t++) {
for (int i = 0; i < 3; i++) a[i] = rand() % 10;
if (brute(a, 3) != fast(a, 3)) break;
}
if (t > 1000) printf("All 1000 tests passed\n");
else printf("Test %d FAILED: a = %d %d %d, brute=%d fast=%d\n", t, a[0], a[1], a[2], brute(a, 3), fast(a, 3));
return 0;
}প্রথম কয়েকটি টেস্টের মধ্যেই অমিল ধরা পড়ে, আর আউটপুটে দেখবেন a[0] সবচেয়ে বড় সংখ্যা এবং fast-এর উত্তর তার বর্গ। কারণ: i2 শুরু হয়েছে 0 থেকে। সবচেয়ে বড়টি নিজেই ঘর 0-তে থাকলে কোনো a[i] তার চেয়ে বড় হয় না, তাই i2 0-তেই থেকে যায় — একই সংখ্যা দুবার। সংশোধন: i2 = -1 দিয়ে শুরু করে শর্ত লিখুন i != i1 && (i2 == -1 || a[i] > a[i2]). তারপর আবার চালান — “All 1000 tests passed” আসা উচিত। srand(42)-এর মতো স্থির random seed রাখার কারণ: প্রতিবার একই টেস্ট আসে, তাই ভুলটি বারবার তৈরি করে দেখা যায়।
ভালো stress test-এর তিনটি গোপন কথা। (১) ছোট ইনপুট দিয়ে শুরু করুন — n = ২ থেকে ৬, যাতে অমিল হলে হাতে বোঝা যায়। (২) মানের পরিসর বদলে বদলে দেখুন — ছোট মান যুক্তির ভুল ধরে, বড় মান overflow ধরে, শূন্য ও ঋণাত্মক মান edge case ধরে। (৩) Brute-কে যতটা সম্ভব বোকা রাখুন — চালাকি করলে brute-এ ভুল ঢুকবে, তখন কার সাথে কাকে মেলাচ্ছেন বোঝা যাবে না।
৮ · উন্নতির পদ্ধতি — অনুশীলন, upsolving আর দলগত খেলা
কনটেস্টে ভালো করার কোনো গোপন রহস্য নেই — আছে একটি অনুশীলনের পদ্ধতি। একজন ব্যাটসম্যান শুধু ম্যাচ খেলে উন্নতি করেন না; কোন বলে আউট হয়েছিলেন, তা নিয়ে নেটে আলাদা করে কাজ করেন। প্রোগ্রামিংয়েও তাই।
🎯 ঠিক মাপের সমস্যা
খুব সহজ সমস্যায় কিছু শেখা হয় না, খুব কঠিনে শুধু হতাশা। এমন সমস্যা বাছুন যা ৩০–৬০ মিনিট চেষ্টায় কখনো পারেন, কখনো পারেন না। অনেক প্ল্যাটফর্মে সমস্যার কঠিনতা অনুযায়ী ছাঁকনি আছে।
নিজের স্তরের একটু ওপরে🔄 Upsolving
কনটেস্টে যে সমস্যা পারেননি, পরে সেটি সমাধান করাকে বলে upsolving. বেশিরভাগ উন্নতি এখানেই হয় — কারণ ঠিক এই সমস্যাগুলোই আপনার জ্ঞানের ফাঁক দেখিয়ে দেয়।
সবচেয়ে কাজের অভ্যাস📖 সৎ চেষ্টার পর editorial
প্রতিটি কনটেস্টের পর editorial প্রকাশ হয়। কিন্তু পাঁচ মিনিট ভেবেই খুলে ফেললে শেখা হয় সামান্য। নিজে সত্যিকারের চেষ্টা করুন, তারপর editorial-এর শুধু প্রথম ইঙ্গিতটুকু পড়ে আবার চেষ্টা করুন।
আগে চেষ্টা, পরে উত্তর📓 ভুলের খাতা
প্রতিটি WA-র কারণ এক লাইনে লিখে রাখুন: “int overflow — দুটি 1e9 গুণ”, “reset ভুলেছি — visited array”. কয়েক মাস পর দেখবেন একই পাঁচ-ছয়টি ভুল ঘুরেফিরে আসছে। সেগুলোই আপনার ব্যক্তিগত চেকলিস্ট।
নিজের ভুল থেকে শেখাICPC — তিনজন, একটি কম্পিউটার
ICPC-র সবচেয়ে মজার দিক হলো দলগত খেলা। তিনজন মানুষ, কিন্তু কিবোর্ড একটি। তাই কে কখন কম্পিউটারে বসবেন, সেটিই বড় কৌশল। ভালো দলগুলো শুরুতে সবাই মিলে সমস্যাগুলো পড়ে সহজটি খুঁজে নেয়, সমাধান কাগজে পরিষ্কার না হলে কম্পিউটারে বসে না, আর WA এলে কোড প্রিন্ট করে উঠে যায় যাতে অন্যজন বসতে পারেন। ভাবনার প্রশ্ন ৪-এ এই কৌশল নিয়ে বিস্তারিত আলোচনা আছে।
একটি ভালো ICPC দল যেন একটি রেস্টুরেন্টের রান্নাঘর — চুলা একটিই, তাই একজন রাঁধেন, একজন সবজি কাটেন, একজন পরের অর্ডারের মসলা তৈরি রাখেন। চুলা এক মুহূর্তও খালি থাকে না। যে দল এই সমন্বয় শিখে যায়, তারা প্রায়ই ব্যক্তিগতভাবে বেশি দক্ষ কিন্তু অগোছালো দলকে হারিয়ে দেয়।
৯ · AI-এর যুগে কনটেস্ট — নিয়ম, সততা আর শেখার সঙ্গী
এখনকার AI মডেলগুলো অনেক কনটেস্ট-সমস্যা সমাধান করতে পারে। তবু মনে রাখুন, কনটেস্ট হলো আপনার চিন্তার মাপকাঠি। ক্রিকেটে বোলিং মেশিন মানুষের চেয়ে নিখুঁত বল করে, তবু কেউ বোলিং মেশিন দিয়ে বিশ্বকাপ খেলায় না।
নিয়ম আগে পড়ুন। Codeforces-সহ অনেক প্ল্যাটফর্ম rated কনটেস্ট চলার সময় AI দিয়ে সমাধান লেখানো বা সমাধানের ভাবনা নেওয়া নিষিদ্ধ করে নিয়ম প্রকাশ করেছে। ICPC-র মতো সরাসরি কনটেস্টে তো ইন্টারনেটই থাকে না। নিয়ম প্ল্যাটফর্ম ও কনটেস্ট ভেদে আলাদা, আর সময়ের সাথে বদলায় — তাই প্রতিটি কনটেস্টে অংশ নেওয়ার আগে সেটির নিয়ম নিজে পড়ে নিন। নিয়ম ভাঙলে অ্যাকাউন্ট বাতিল হতে পারে, আর তার চেয়েও বড় ক্ষতি — নিজেকে ঠকানো।
তবে কনটেস্টের পরে AI একজন অসাধারণ শিক্ষক। নিজে সৎভাবে চেষ্টা করে editorial পড়েছেন, কিন্তু একটি ধাপ বুঝছেন না — তখন AI-কে প্রশ্ন করুন। শর্ত একটাই: উত্তর নয়, বোঝাপড়া চান।
Upsolving-এর সময় নিচের কাঠামোয় প্রশ্ন করুন। খেয়াল করুন — আপনি পুরো কোড চাইছেন না, চাইছেন ভাবনার পথ আর আপনার নিজের ভুলের ব্যাখ্যা:
AI-এর দেওয়া সমাধান যাচাইয়ের চেকলিস্ট
AI প্রায়ই নমুনায় ঠিক উত্তর দেয়, কিন্তু সীমার কাছে ভুল করে। অনুশীলনে বা চাকরিতে AI-এর লেখা অ্যালগরিদম যাচাইয়ে কনটেস্টের এই অভ্যাসগুলোই কাজে লাগে।
কনটেস্টের পরে AI হতে পারে আপনার শিক্ষক — উত্তরদাতা নয়।
১০ · মডিউল ৬-এর সমাপ্তি — আপনার অ্যালগরিদমের টুলবক্স
এই পর্ব দিয়ে মডিউল ৬ শেষ হলো। ছয়টি পর্বে আপনি এমন একটি টুলবক্স হাতে পেয়েছেন, যা কনটেস্টে, চাকরির ইন্টারভিউতে আর বাস্তব সফটওয়্যারে — তিন জায়গাতেই কাজে লাগে। একবার পেছনে তাকিয়ে দেখি:
| পর্ব | যে টুল পেলেন | কখন হাতে নেবেন |
|---|---|---|
| ৩৯ · কমপ্লেক্সিটি | Big-O দিয়ে কোড না চালিয়েই গতির অনুমান | প্রতিটি সমস্যার শুরুতে, constraints পড়ার সাথে সাথে |
| ৪০ · সর্টিং | ডেটা সাজিয়ে সমস্যা সহজ করা | জোড়া খোঁজা, ক্রম, কাছাকাছি মান |
| ৪১ · সার্চিং ও Divide & Conquer | প্রতি ধাপে খোঁজার জায়গা অর্ধেক করা | সাজানো ডেটায় খোঁজা, “সর্বনিম্ন কত হলে সম্ভব” |
| ৪২ · ডায়নামিক প্রোগ্রামিং | ছোট সমস্যার উত্তর জমিয়ে বড়টির সমাধান | গণনা, সর্বোচ্চ/সর্বনিম্ন, একই উপ-সমস্যা বারবার |
| ৪৩ · Greedy ও নাম্বার থিওরি | প্রতি ধাপে সেরা পছন্দ; ভাগশেষ ও মৌলিক সংখ্যার হিসাব | সময়সূচি, মুদ্রা, বড় সংখ্যার ভাগশেষ |
| ৪৪ · কনটেস্ট কৌশল | Constraints পড়া, ফাঁদ চেনা, stress testing | সব সময় — বিশেষ করে জমা দেওয়ার আগে |
অ্যালগরিদম শেখা মানে শত শত কোড মুখস্থ করা নয়। মানে হলো — সমস্যা দেখে তার আকার মাপা, চেনা ছাঁচ খোঁজা, খরচ হিসাব করা, আর সমাধানটি সঠিক কি না যন্ত্র দিয়ে যাচাই করা। AI যখন কোড লিখে দিতে পারে, তখন এই বিচারবুদ্ধিই আপনাকে আলাদা করবে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলোই আপনাকে কোড-লেখক থেকে সিস্টেম-চিন্তক বানাবে।
প্র ০১কনটেস্টের দক্ষতা কি আসল চাকরিতে কাজে লাগে? কোথায় মেলে, আর কোথায় একদম মেলে না?
সৎ উত্তর হলো — অনেকখানি কাজে লাগে, কিন্তু পুরোটা নয়। দুই দিকই বোঝা দরকার।
- যেখানে সরাসরি মেলে — ইন্টারভিউ: বড় সফটওয়্যার কোম্পানিগুলোর কারিগরি ইন্টারভিউয়ের বড় অংশ এখনো অ্যালগরিদমিক সমস্যা — সীমিত সময়ে বুঝে, গতি হিসাব করে, কোড লেখা। বাংলাদেশের অনেক সফটওয়্যার কোম্পানিও নিয়োগে কনটেস্টের অভিজ্ঞতাকে গুরুত্ব দেয়।
- যেখানে চিন্তার অভ্যাস মেলে: “এই কোড ১০ লাখ ব্যবহারকারীতে টিকবে তো?” — এই প্রশ্ন করার অভ্যাস কনটেস্ট থেকেই আসে। Edge case নিয়ে সন্দেহ, overflow নিয়ে সতর্কতা, stress testing — এগুলো পেশাদার সফটওয়্যারে সরাসরি কাজে লাগে।
- যেখানে মেলে না — দীর্ঘ জীবনের কোড: কনটেস্টের কোড ২০ মিনিটে লেখা হয়, একবার চলে, তারপর ফেলে দেওয়া হয়। আসল সফটওয়্যার বছরের পর বছর বেঁচে থাকে, দশজন মিলে বদলায়। সেখানে ভ্যারিয়েবলের পরিষ্কার নাম, ছোট ফাংশন, টেস্ট, ডকুমেন্টেশন — এগুলো গতির চেয়ে বেশি গুরুত্বপূর্ণ। এক অক্ষরের নাম আর ম্যাক্রো-ভরা কনটেস্টের কোড কোম্পানির কোডবেসে চলবে না।
- যেখানে কনটেস্ট শেখায় না: অস্পষ্ট চাহিদা থেকে সমস্যা খুঁজে বের করা। কনটেস্টে সমস্যা সুনির্দিষ্টভাবে লেখা থাকে; বাস্তবে গ্রাহক বলেন “অ্যাপটা একটু দ্রুত করে দিন” — কোথায় ধীর, কেন ধীর, আদৌ সমস্যা কি না, সব আপনাকেই বের করতে হয়।
তাই সেরা পথ হলো দুটোকে মেলানো — কনটেস্ট দিয়ে চিন্তার পেশি গড়া, আর প্রজেক্ট দিয়ে (যেমন পর্ব ২৩-এর CLI টুল) টেকসই কোড লেখার অভ্যাস।
মূল উপলব্ধি: কনটেস্ট হলো জিমের মতো — শরীর শক্ত করে, কিন্তু জিমে ওজন তোলা আর বাড়ি বানানো এক কাজ নয়। শক্তি কাজে লাগে, তবে নির্মাণের কৌশল আলাদা করে শিখতে হয়।
প্র ০২জাজ কেন টেস্টগুলো গোপন রাখে, আর কেন সময়সীমা দেয়? নমুনা মিললেই তো সমাধান ঠিক হওয়ার কথা, তাই না?
না — আর এই “না”-টিই সফটওয়্যার টেস্টিংয়ের সবচেয়ে গভীর শিক্ষাগুলোর একটি।
গোপন টেস্ট কেন: টেস্টগুলো দেখা গেলে যে কেউ শুধু সেগুলোর উত্তর ছাপিয়ে দিতে পারত — প্রোগ্রাম কিছুই হিসাব না করে if (input == ...) দিয়ে উত্তর বলে দিত। গোপন রাখায় আপনাকে সাধারণ সমাধান লিখতে হয়, যা যেকোনো বৈধ ইনপুটে কাজ করে। আসল সফটওয়্যারও তাই — ব্যবহারকারী কোন ইনপুট দেবেন, তা আগে থেকে জানা যায় না।
নমুনা কেন যথেষ্ট নয়: নমুনা দু-একটি সহজ উদাহরণ, সমস্যা বোঝানোর জন্য। আর সমস্যা-লেখকরা গোপন টেস্ট বানান ইচ্ছা করে ভাঙার জন্য — n = 1, সব সংখ্যা সমান, সব ঋণাত্মক, সর্বোচ্চ মান, সর্বোচ্চ n, আগে থেকেই সাজানো ইনপুট (যেখানে কিছু সর্টিং পদ্ধতি সবচেয়ে ধীর হয়)। ভালো টেস্ট সেট আসলে সম্ভাব্য ভুলের একটি মানচিত্র।
সময়সীমা কেন: সময়সীমা ছাড়া প্রতিটি সমস্যাই brute force দিয়ে সমাধান হয়ে যেত — সব সম্ভাবনা যাচাই করলেই হলো, ঘণ্টা লাগলে লাগুক। সময়সীমা বাধ্য করে দক্ষ অ্যালগরিদম খুঁজতে। লেখক সাধারণত নিজের সমাধানের চেয়ে কয়েক গুণ বেশি সময় দেন, যাতে সঠিক পদ্ধতির যেকোনো যুক্তিসংগত বাস্তবায়ন পাস করে, কিন্তু ধীর পদ্ধতি না পারে। বাস্তবেও bKash-এর লেনদেন “শেষ পর্যন্ত” ঠিক হলেই চলে না, সেকেন্ডের মধ্যে হতে হয়।
এখান থেকে একটি পেশাদার অভ্যাস তৈরি হয়: নিজের কোডের জন্য নিজেই “গোপন টেস্ট” ভাবা। জমা দেওয়ার আগে প্রশ্ন করুন — কোন ইনপুটে আমার কোড ভাঙতে পারে? সেটিই boundary value ভিত্তিক টেস্টিং।
মূল উপলব্ধি: “আমার উদাহরণে চলে” আর “সব বৈধ ইনপুটে চলে” — এই দুইয়ের মাঝের ফাঁকেই প্রায় সব বাগ থাকে। গোপন টেস্ট আপনাকে সেই ফাঁক নিয়ে ভাবতে বাধ্য করে।
প্র ০৩কোড মনোযোগ দিয়ে পড়ার চেয়ে stress testing কেন বেশি কার্যকর? মানুষের মস্তিষ্ক কি ভুল ধরতে খারাপ?
মস্তিষ্ক খারাপ নয় — কিন্তু নিজের লেখা কোড পড়ার সময় সে একটি বিশেষ ফাঁদে পড়ে।
- যা ভেবেছেন, তাই দেখেন: আপনি যখন নিজের কোড পড়েন, মস্তিষ্ক আসলে কোডটি পড়ে না — পড়ে আপনার মনের ভেতরের উদ্দেশ্যটি। আপনি জানেন
i2“দ্বিতীয় বৃহত্তম” রাখার কথা, তাই প্রতিবার পড়ার সময় ধরে নেন সে তাই রাখছে। - কল্পনার সীমা: কোড পড়ে আপনি হয়তো পাঁচ-দশটি ইনপুট মাথায় চালাতে পারেন — আর সেগুলোও আপনার চেনা ধরনের। Stress test সেকেন্ডে হাজার হাজার ইনপুট চালায়, যার অনেকগুলো এমন, যা আপনার মাথায় কখনো আসত না।
- অনুমান বনাম প্রমাণ: কোড পড়ে আপনি বলেন “মনে হয় ঠিক আছে।” Stress test বলে “এই নির্দিষ্ট ইনপুটে ভুল” — একটি অস্বীকার করা যায় না এমন প্রমাণ।
তবে stress testing-এরও সীমা আছে। এটি ভুলের উপস্থিতি দেখাতে পারে, অনুপস্থিতি প্রমাণ করতে পারে না — হাজার টেস্ট পাস মানে সমাধান নিশ্চিত সঠিক নয়। Brute force নিজেই ভুল হলে দুই ভুলে মিলও হতে পারে। আর কিছু ভুল শুধু খুব বড় ইনপুটে আসে (যেমন TLE বা stack overflow), যা brute চালাতে পারে না। তাই বড় n-এ গতির পরীক্ষা আলাদা করে করতে হয়।
পেশাদার জগতে এই ভাবনারই বড় রূপ হলো differential testing আর fuzzing — যেমন দুটি ভিন্ন compiler-এ একই এলোমেলো প্রোগ্রাম চালিয়ে ফল মেলানো। এভাবে GCC ও Clang-এর মতো পরিণত compiler-এও বহু বাগ ধরা পড়েছে। AI-এর লেখা কোড যাচাইয়েও এটিই সবচেয়ে নির্ভরযোগ্য পদ্ধতিগুলোর একটি: AI-এর দ্রুত সমাধানকে নিজের লেখা সরল সমাধানের সাথে মিলিয়ে দেখা।
মূল উপলব্ধি: মানুষ যুক্তি দিয়ে ভালো ভাবে, যন্ত্র ক্লান্তিহীনভাবে যাচাই করে। ভালো প্রকৌশলী দুটিকে মেলান — মাথা দিয়ে সমাধান, যন্ত্র দিয়ে সন্দেহ।
প্র ০৪ICPC-তে তিনজনের দল, কিন্তু কম্পিউটার একটি। তাহলে দল আসলে কীভাবে সময় কাজে লাগায়, আর সেরা কৌশল কী?
“একটি কম্পিউটার” নিয়মটিই ICPC-কে ব্যক্তিগত প্রতিযোগিতা থেকে একটি ব্যবস্থাপনার সমস্যা বানিয়ে দেয়। কম্পিউটার হলো সবচেয়ে দুর্লভ সম্পদ — ঠিক যেন একটি কারখানার একমাত্র দামি মেশিন। লক্ষ্য হলো সেটিকে এক মুহূর্তও অলস না রাখা, আর ভুল কাজে নষ্ট না করা।
- ভূমিকা ভাগ: অনেক দলে একজন দ্রুত ও নির্ভুল টাইপিস্ট (“কোডার”), একজন গাণিতিক বা কঠিন সমস্যার বিশেষজ্ঞ, আর একজন যিনি সমস্যা পড়ে বাছাই করেন ও অন্যদের সমাধান যাচাই করেন।
- কাগজে আগে, কম্পিউটারে পরে: সমাধান পুরোপুরি পরিষ্কার না হলে কম্পিউটারে বসা নিষেধ — এটি অনেক দলের নিয়ম। কম্পিউটারে বসে ভাবা মানে বাকি দুজনের সময় নষ্ট।
- WA এলে উঠে যাওয়া: ভুল খোঁজার জন্য কম্পিউটার আটকে না রেখে কোড প্রিন্ট করে কাগজে খোঁজা, আর এই ফাঁকে অন্যজন নিজের সমস্যা লেখেন।
- সমস্যার ক্রম: ICPC-তে স্কোর হয় কয়টি সমস্যা সমাধান করেছেন তা দিয়ে, সমান হলে মোট সময় (penalty) দিয়ে। তাই সহজ সমস্যাগুলো যত দ্রুত সম্ভব শেষ করা জরুরি — প্রতিটি সমাধানের সময় penalty-তে যোগ হয়।
- দ্বিতীয় জোড়া চোখ: জমা দেওয়ার আগে অন্য একজন সমাধানের যুক্তি শোনেন। নিজের যুক্তি জোরে বলতে গেলেই অনেক ভুল ধরা পড়ে।
এই অভিজ্ঞতা সরাসরি পেশাদার জীবনে কাজে লাগে। Code review, pair programming, চাপের মধ্যে শান্ত থেকে সিদ্ধান্ত নেওয়া — সবকিছুর অনুশীলন ICPC-র পাঁচ ঘণ্টায় হয়ে যায়।
মূল উপলব্ধি: তিনজন সেরা ব্যক্তি মিলেই সেরা দল হয় না। দুর্লভ সম্পদ (এখানে কম্পিউটার) কীভাবে ভাগ হবে, আর কে কখন কী করবে — এই ব্যবস্থাপনাই ফল ঠিক করে দেয়।
প্র ০৫AI যখন অনেক কনটেস্ট-সমস্যা নিজেই সমাধান করতে পারে, তখন কনটেস্ট আর চাকরির ইন্টারভিউ কীভাবে বদলাচ্ছে? এখনো কি অ্যালগরিদম শেখার মানে আছে?
এটি এই মুহূর্তের সবচেয়ে জীবন্ত প্রশ্নগুলোর একটি, আর উত্তর এখনো তৈরি হচ্ছে। তবে কয়েকটি প্রবণতা পরিষ্কার।
- অনলাইন কনটেস্টে নতুন নিয়ম: AI-এর ক্ষমতা বাড়ার সাথে সাথে প্ল্যাটফর্মগুলো rated কনটেস্টে AI ব্যবহারের নিয়ম কড়া করেছে, আর সন্দেহজনক জমা খোঁজার চেষ্টা বাড়িয়েছে। সরাসরি উপস্থিত থেকে, ইন্টারনেট ছাড়া কম্পিউটারে হওয়া কনটেস্ট (যেমন ICPC-র আঞ্চলিক পর্ব) তুলনামূলকভাবে সুরক্ষিত, তাই সেগুলোর গুরুত্ব হয়তো আরও বাড়বে।
- ইন্টারভিউয়ের ধরন বদলাচ্ছে: অনলাইন কোডিং টেস্টে AI দিয়ে প্রতারণার সুযোগ থাকায় অনেক কোম্পানি সরাসরি বা ভিডিওতে কথোপকথনভিত্তিক ইন্টারভিউয়ে জোর দিচ্ছে — “এই সমাধান কেন কাজ করে?”, “n দশ গুণ হলে কী হবে?”, “এখানে কোন edge case ভাঙতে পারে?” কিছু কোম্পানি আবার AI ব্যবহারের অনুমতি দিয়ে দেখছে প্রার্থী AI-এর ভুল ধরতে পারেন কি না।
- যা বদলাচ্ছে না: দুই ক্ষেত্রেই মাপা হচ্ছে বোঝাপড়া — সমস্যার আকার মাপা, খরচ হিসাব করা, সমাধান যাচাই করা। AI কোড লিখে দিলে এই দক্ষতার দাম কমে না, বরং বাড়ে। কারণ AI-এর সমাধান ১০০ বারে ৯৫ বার ঠিক হলে বাকি ৫ বার ধরতে পারা মানুষটিই দলের সবচেয়ে মূল্যবান সদস্য।
তাহলে অ্যালগরিদম শেখার মানে কী? ক্যালকুলেটর আসার পরও আমরা নামতা শিখি — হিসাব করার জন্য নয়, কোন উত্তর অসম্ভব তা চোখে ধরার জন্য। AI যদি বলে “এই O(n2) সমাধান ১০৬ ইনপুটে এক সেকেন্ডে চলবে”, আপনি এক নজরে বুঝবেন সেটি ভুল — কারণ আপনি জানেন ১০১২ কাজ এক সেকেন্ডে হয় না।
মূল উপলব্ধি: AI যত শক্তিশালী হবে, মানুষের কাজ তত সরে যাবে “লেখা” থেকে “বিচার করা”-র দিকে। আর ভালো বিচারক হতে হলে নিজে খেলাটা খেলতে হয়।
অনুশীলন
এগুলোর বেশিরভাগে কোড লিখতে হবে না — হিসাব করা, চিনে ফেলা আর পরিকল্পনা করাই আসল কাজ।
-
Constraints থেকে গতি: সময়সীমা ১ সেকেন্ড ধরে প্রতিটির জন্য বলুন কোন গতির অ্যালগরিদম লাগবে — (ক) n ≤ ১৮ (খ) n ≤ ২০০০ (গ) n ≤ ৫ × ১০৫ (ঘ) n ≤ ১০১৮
(ক) ২১৮ প্রায় ২.৬ লাখ, তাই O(2n) বা O(2n · n) চলবে — সব উপসেট যাচাই বা bitmask DP-র ইঙ্গিত।
(খ) n2 = ৪০ লাখ — আরামে চলবে। n3 = ৮ × ১০৯ — অনেক বেশি। তাই O(n2), যেমন দুই মাত্রার DP.
(গ) n2 = ২.৫ × ১০১১, অসম্ভব। লাগবে O(n log n) বা O(n) — সর্টিং, binary search, prefix sum.
(ঘ) এত বড় n-এ একটি লুপও চালানো যাবে না। লাগবে O(log n) বা O(1) — সূত্র, binary search বা দ্রুত ঘাত, সাথে
long long. -
Verdict গোয়েন্দা: প্রতিটি ক্ষেত্রে সম্ভাব্য কারণ বলুন — (ক) নমুনা মেলে, কিন্তু test 1-এ WA (খ) n ≤ ১০৬, কোডে
int a[1000000];main-এর ভেতরে, RE (গ) n ≤ ১০৫, দুই স্তরের লুপ, TLE (ঘ) সব ছোট টেস্ট পাস, test 15-এ WA, উত্তর ঋণাত্মক এসেছে অথচ সব সংখ্যা ধনাত্মক(ক) test 1 সাধারণত নমুনাই — তাই সম্ভাব্য কারণ আউটপুটের ফরম্যাট (বাড়তি লেখা, “Case” বানান), অথবা এমন uninitialized ভ্যারিয়েবল যা আপনার কম্পিউটারে কাকতালীয়ভাবে 0 ছিল।
(খ) প্রায় ৪ MB-র লোকাল array stack-এ জায়গা পায়নি — stack overflow. Array-টি
main-এর বাইরে global করুন।(গ) n2 = ১০১০ — অ্যালগরিদমই ধীর। Fast I/O সাহায্য করবে না; n log n পদ্ধতি খুঁজুন।
(ঘ) ধনাত্মক সংখ্যার যোগ বা গুণে ঋণাত্মক উত্তর প্রায় নিশ্চিতভাবে
intoverflow.long long,%lldআর গুণের আগে cast দেখুন। -
বাগ সারান, আবার stress test: উপরের
stress.cপ্রোগ্রামেরfastফাংশনটি ঠিক করুন, তারপর আবার চালান। এরপরrand() % 10-এর জায়গায়rand() % 100000দিয়ে চালান — নতুন কোনো সমস্যা দেখা দেয় কি?সংশোধিত দ্বিতীয় লুপ:
int i2 = -1;এবংfor (int i = 0; i < n; i++) if (i != i1 && (i2 == -1 || a[i] > a[i2])) i2 = i;— এখন “All 1000 tests passed” আসবে।মান ১ লাখ পর্যন্ত নিলে দুটি গুণ করলে ১০১০ পর্যন্ত হতে পারে, যা
int-এ ধরে না। দুই ফাংশনেই overflow হয় — আর মজার ব্যাপার, দুটিই একইভাবে ভুল করলে stress test অমিল দেখাবে না! এটি stress testing-এর একটি সীমা: brute নিজেও ভুল হলে ভুলটি লুকিয়ে যায়। সমাধান: দুই ফাংশনেইlong longআর(long long)a[i] * a[j]. -
নিজের অনুশীলন-পরিকল্পনা: Codeforces, AtCoder বা Toph-এ একটি অ্যাকাউন্ট খুলুন (অথবা ইতিমধ্যে থাকলে সেটি দেখুন)। আগামী চার সপ্তাহের একটি পরিকল্পনা লিখুন — সপ্তাহে কয়টি কনটেস্ট, কয়টি upsolving, আর ভুলের খাতার একটি নমুনা লাইন কেমন হবে।
একটি বাস্তবসম্মত শুরু হতে পারে:
- সপ্তাহে ১টি কনটেস্ট (AtCoder-এর Beginner Contest বা Codeforces-এর Div. 3/Div. 4 নতুনদের জন্য ভালো)।
- প্রতিটি কনটেস্টের পর অন্তত ১টি না-পারা সমস্যার upsolving — নিজে চেষ্টা, তারপর editorial-এর ইঙ্গিত, তারপর নিজে লেখা।
- সপ্তাহে ৫–৭টি নিজের স্তরের একটু ওপরের সমস্যা, একটি বিষয় ধরে — যেমন এক সপ্তাহ শুধু binary search-এর সমস্যা।
- ভুলের খাতার লাইন: “২০ অক্টোবর · prefix sum সমস্যা · WA test 9 · কারণ: pre[] int ছিল, মান ১০৯ · শিক্ষা: যোগফলের array সবসময় long long”.
পরিমাণের চেয়ে নিয়মিততা বেশি গুরুত্বপূর্ণ। চার সপ্তাহ পর খাতায় যে ভুলটি সবচেয়ে বেশি পাবেন, সেটিই পরের মাসের মনোযোগের বিষয়।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমWA পাওয়ার পর stress test-এর ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- 🐢 একটি সরল brute force সমাধান লেখা
- 🎲 ছোট এলোমেলো ইনপুট বানানোর প্রোগ্রাম লেখা
- 🔁 একই ইনপুটে brute ও দ্রুত সমাধান চালিয়ে উত্তর মেলানো
- 🔍 অমিল পেলে থেমে সেই ছোট ইনপুটটি দেখা
- 🛠️ ভুল সারিয়ে আবার stress test চালিয়ে তারপর জমা দেওয়া
একটি সমস্যায় n ≤ ২ × ১০৫, সময়সীমা ১ সেকেন্ড। কোন গতির সমাধান লক্ষ্য করা উচিত?
- O(2n)
- O(n2)
- O(n log n)
- O(n3)
জাজ জানাল TLE. প্রথমে কোন সন্দেহটি সবচেয়ে যুক্তিসংগত?
- উত্তরের ফরম্যাটে একটি বাড়তি space আছে
- অ্যালগরিদম constraints-এর তুলনায় ধীর, বা কোথাও অসীম লুপ
- কোডে syntax-এর ভুল আছে
- মেমরি বেশি লাগছে
int a = 1000000000, b = 1000000000; — দুটির গুণফল নিরাপদে পেতে কোনটি লিখবেন?
long long p = a * b;int p = a * b;float p = a * b;long long p = (long long)a * b;
নমুনায় একটি test case, ফল ঠিক। কিন্তু জাজের টেস্টে অনেকগুলো test case, আর দ্বিতীয়টি থেকে উত্তর ভুল আসছে। সবচেয়ে সম্ভাব্য কারণ?
- যোগফল বা গণনার ভ্যারিয়েবল প্রতিটি test case-এর শুরুতে reset হচ্ছে না
- অ্যালগরিদমটি বেশি ধীর
- জাজের compiler আলাদা
- Fast I/O ব্যবহার না করা
Stress test প্রোগ্রামে srand(time(NULL))-এর বদলে srand(42)-এর মতো স্থির seed রাখার মূল সুবিধা কী?
- প্রোগ্রাম দ্রুত চলে
- স্থির seed বেশি এলোমেলো সংখ্যা দেয়
- প্রতিবার একই টেস্ট আসে, তাই ভুলটি বারবার তৈরি করে দেখা যায়
- Compiler warning দেয় না
Codeforces-এর একটি rated কনটেস্ট চলছে, একটি সমস্যায় আটকে গেছেন। সঠিক আচরণ কোনটি?
- AI-কে সমস্যা দিয়ে সমাধান নিয়ে জমা দেওয়া
- কনটেস্টের নিয়ম মেনে নিজে চেষ্টা করা; শেষ হলে editorial পড়ে ও AI-এর সাহায্যে বুঝে upsolving করা
- বন্ধুকে মেসেজ করে সমাধানের ইঙ্গিত চাওয়া
- সমস্যাটি চিরতরে বাদ দেওয়া — কঠিন সমস্যা আমার জন্য নয়
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- কনটেস্টে সমাধানকে হতে হয় সঠিক, দ্রুত ও মেমরি-সাশ্রয়ী; প্রতিটি verdict (AC, WA, TLE, MLE, RE, CE) খোঁজার দিক দেখায়।
- লেখার আগে constraints পড়ুন: এক সেকেন্ডে প্রায় ১০৮ সহজ কাজ ধরে প্রয়োজনীয় গতি হিসাব করুন।
- চেনা ফাঁদ: int overflow (
long long,%lld), reset ভুলে যাওয়া, বড় লোকাল array, off-by-one, আউটপুটের ফরম্যাট। - WA-তে আটকালে কোড তাকিয়ে না থেকে stress test: brute + fast + এলোমেলো ইনপুট, ছোট থেকে বড় মান পর্যন্ত।
- উন্নতি আসে upsolving আর ভুলের খাতা থেকে; কনটেস্টের নিয়ম মেনে চলুন, আর AI-কে ব্যবহার করুন কনটেস্টের পরে শেখার জন্য।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ৪৫ · উন্নত পয়েন্টার — const, restrict, volatileপরবর্তী পর্বমডিউল ৭ শুরু — সিস্টেম প্রোগ্রামিংয়ের পথে প্রথম পদক্ষেপ।
- C প্রোগ্রামিং · কোর্স হোম৫৬টি পর্বপুরো কোর্সের রোডম্যাপ — কোন পর্ব কখন।
- Data Structures & Algorithmsগভীরে যানsegment tree, union-find সহ কনটেস্টে লাগে এমন আরও ডেটা স্ট্রাকচার।
- Design & Analysis of Algorithmsগভীরে যানঅ্যালগরিদম সঠিক কেন, তার প্রমাণ আর গতির নিখুঁত বিশ্লেষণ।
- C++ প্রোগ্রামিংপাশের ট্র্যাকবেশিরভাগ প্রতিযোগী C++ ব্যবহার করেন — তৈরি sort, map, vector নিয়ে।
- Software Testing & QAপাশের ট্র্যাকStress testing-এর পেশাদার রূপ — fuzzing, property-based ও regression testing.