সমস্যা ১ – জোড়-বিজোড় ১

সমস্যার বিবরণ

কোনো একটি পূর্ণসংখ্যা দেওয়া থাকবে, সেটি জোড় না বিজোড় তা বের করতে হবে।
(সমস্যাটির অনলাইন লিঙ্ক: http://bit.ly/1-52-problem-1)

ইনপুট

প্রথম লাইনে একটি সংখ্যা T (1<=T<=100) দেওয়া থাকবে। পরবর্তীতে T-এর মান যত, ততটি লাইন থাকবে। প্রতিটি লাইনে একটি করে পূর্ণসংখ্যা n (0<=n<=2147483647) দেওয়া থাকবে।

আউটপুট

প্রতিটি পূর্ণসংখ্যার জন্য, সংখ্যাটি জোড় হলে even আর বিজোড় হলে odd কথাটি প্রিন্ট করতে হবে।

উদাহরণ

ইনপুট আউটপুট
3
100
0
1111
even
even
odd
সমাধান দেখুন

সমাধান

জোড়-বিজোড় সংখ্যার সঙ্গে ছোটবেলা থেকেই তোমরা পরিচিত। সমস্যার বর্ণনায় প্রথমেই বলা আছে কোনো একটি সংখ্যা দেওয়া থাকলে সেটি জোড় না বিজোড় তা বের করতে হবে। খুবই সহজ একটি সমস্যা (মানে সমাধান সহজ আর কী)।

যেকোনো প্রোগ্রামিং করার আগে সেটি মনোযোগ দিয়ে পড়ে নিতে হবে। প্রথমেই ইনপুট/আউটপুটের দিকে খেয়াল কর। ইনপুটে বলা আছে প্রথম লাইনে একটি পূর্ণ সংখ্যা T থাকবে। T-এর মান যত পরবর্তী ঠিক ততটি লাইনে একটি করে পূর্ণ সংখ্যা n দেওয়া থাকবে। এখানে দেখ, পূর্ণ সংখ্যাটির একটি রেঞ্জ দেওয়া আছে 0 থেকে 2147483647-এর মধ্যে। তোমরা যে int টাইপের ভ্যারিয়েবল ব্যবহার কর সেটির সর্বোচ্চ মান হচ্ছে 2147483647। তার মানে int টাইপের ভ্যারিয়েবল ব্যবহার করলেই চলবে।

উদাহরণ ইনপুটে দেখ, প্রথম লাইনে দেওয়া আছে 3 এবং পরবর্তী তিনটি লাইনে তিনটি আলাদা আলাদা সংখ্যা, 100, 0, 1111 দেওয়া আছে। এবার আউটপুটে দেখ, প্রথম সংখ্যা 100-এর জন্য আউটপুটে আছে even, দ্বিতীয় সংখ্যা 0-এর জন্য আউটপুটে দেওয়া আছে even, তৃতীয় সংখ্যা 1111-এর জন্য আউটপুটে দেওয়া আছে odd।

এবার আমাদের কোড লেখার পালা। প্রথমেই main() ফাংশনে ভ্যারিয়েবল ডিক্লেয়ার করে নিতে হবে।

int T, i, n;

T ব্যবহার করব প্রথম ইনপুটটি নেওয়ার জন্য (যেটি নির্দেশ করবে যে এর পর আর কয়টি সংখ্যা আছে), i ব্যবহার করব for লুপের ইনডেক্স হিসেবে আর n হচ্ছে আমরা T-সংখ্যক লাইনে যে সংখ্যাগুলো ইনপুট হিসেবে নেব সে জন্য। এ জন্য আমরা T-এর মান ইনপুট নেব।

scanf("%d", &T);

for লুপটি T সংখ্যকবার চলবে।

for(i = 1; i <= T; i++) { }

লুপ চলার সময় প্রতিবার আমরা n-এর মান ইনপুট নিব।

scanf("%d", &n);

যদি n দুই দ্বারা বিভাজ্য হয় তাহলে প্রিন্ট করব even। অন্যথায় প্রিন্ট করব odd।

if (n % 2 == 0)
{
    printf("even\n");
}
else
{
    printf("odd\n");
}

সমস্যার বর্ণনায় নিউলাইন প্রিন্ট করার কথা বলা না থাকলেও আমি দুটি printf()-এর শেষে একটি করে নিউলাইন প্রিন্ট করেছি। কারণ, লক্ষ করে দেখো উদাহরণ আউটপুটে even, odd এগুলো প্রতিটি নতুন লাইনে প্রিন্ট করা আছে।

মনে রাখতে হবে, সমস্যার বর্ণনায় বলা আছে ঠিক সেভাবেই আউটপুট প্রিন্ট করতে হবে। অনেক সময় দেখা যায় তোমরা নিজেদের ইচ্ছামতো “This is an even number” এভাবে প্রিন্ট করো। আবার অনেক সময় দেখা যায় Even, Odd এভাবে প্রিন্ট করো। এভাবে করা যাবে না। আউটপুটে সব ছোট হাতের অক্ষরে থাকলে ছোট হাতের অক্ষরেই প্রিন্ট করতে হবে, নইলে উত্তর ভুল হবে।

এবার পুরো প্রোগ্রামটি নিচে দেখি:

#include<stdio.h>

int main()
{
    int T, i, n;
    
    scanf("%d", &T);
    
    for(i = 1; i <= T; i++)
    {
        scanf("%d", &n);
        
        if (n % 2 == 0)
        {
            printf("even\n");
        }
        else
        {
            printf("odd\n");
        }
    }
    
    return 0;
}

সমস্যা ২ – জোড়-বিজোড় ২

সমস্যার বিবরণ

কোনো একটি পূর্ণসংখ্যা দেওয়া থাকবে, সেটি জোড় না বিজোড় তা বের করতে হবে।
(সমস্যাটির অনলাইন লিঙ্ক: http://bit.ly/1-52-problem-2)

ইনপুট

প্রথম লাইনে একটি সংখ্যা T (1<=T<=100) দেওয়া থাকবে। পরবর্তীতে T সংখ্যক লাইন একটি করে ঋণাত্মক নয় (Non-negative) পূর্ণসংখ্যা n দেওয়া থাকবে। একটি সংখ্যায় সর্বোচ্চ 100টি অঙ্ক (digit) থাকতে পারে।

আউটপুট

প্রতিটি পূর্ণসংখ্যার জন্য, সংখ্যাটি জোড় হলে even আর বিজোড় হলে odd প্রিন্ট করতে হবে।

উদাহরণ

ইনপুট আউটপুট
3
100
0
1111
even
even
odd
সমাধান দেখুন

সমাধান

তোমার যদি আগের সমস্যাটির সমাধান করা থাকো, তাহলে সেটি আবার জমা দাও। উত্তর কী পেলে? রং আনসার?

আগের সমস্যার সঙ্গে এই সমস্যাটির পার্থক্য কোথায়? মাত্র একটি জায়গায়। বলা আছে যে সংখ্যাটিতে সর্বোচ্চ 100-টি অঙ্ক থাকতে পারে। 100-টি অঙ্ক মানে কিন্তু অনেক বড় সংখ্যা। int ভ্যারিয়েবল হচ্ছে 32 বিট, তার মানে এই ধরনের ভ্যারিয়েবলে 232-টি সংখ্যা রাখা যায়। 232 মানে 4294967296। তাহলে যদি signed int ধরি অর্থাৎ ঋণাত্মক ও ধনাত্মক উভয় ধরনের সংখ্যাই রাখি, তাহলে আমরা -231 থেকে 231-1 পর্যন্ত সংখ্যা (-2147483648 থেকে 2147483647) রাখতে পারব।

আর যদি unsigned int ব্যবহার করা, তাহলে 0 থেকে 4294967295 পর্যন্ত সংখ্যা রাখা যাবে। তোমাদের মনে রাখার জন্য এখানে একটা চার্ট দিয়ে দিলাম।

ডেটা টাইপ সর্বনিম্ন সীমা বা লিমিট সর্বোচ্চ সীমা বা লিমিট মোট সংখ্যা
signed int -231 = -2147483648 231-1 = 2147483647 232 = 4294967296 টি
unsigned int 0 232-1 = 4294967295 232 = 4294967296 টি

আরেক ধরনের ডেটা টাইপ আছে, যাকে long long int এর ফরম্যাট স্পেসিফায়ার হচ্ছে %lld (প্রথম দুইটি এল)। এটি 64 বিট। এখন তোমরা বের করো, এই ভ্যারিয়েবলে কত পর্যন্ত সংখ্যা রাখা যাবে। দেখবে 19 অঙ্কের বেশি নয়। কিন্তু আমাদের দরকার 100 অঙ্কের সংখ্যা রাখতে পারে, এমন ভ্যারিয়েবল!

আসলে এখানে স্ট্রিং ব্যবহার করতে হবে। আর জোড় না বিজোড়, সেটি বোঝা যাবে স্ট্রিংয়ের শেষ ক্যারেক্টারটি বা বর্ণটি পরীক্ষা করলেই। তাহলে আমাদের প্রোগ্রামটি দাঁড়াবে এ রকম:

#include<stdio.h>
#include<string.h> // strlen ব্যবহারের জন্য

int main()
{
    int T, i;
    char n[101]; // 100 অঙ্কের জন্য 101 সাইজের অ্যারে
    int len;

    scanf("%d", &T);

    for(i = 1; i <= T; i++)
    {
        scanf("%s", &n);
        len = strlen(n);
        
        // শেষ অঙ্কটি জোড় কি না তা পরীক্ষা করি
        if ((n[len-1] - '0') % 2 == 0) 
        {
            printf("even\n");
        }
        else 
        {
            printf("odd\n");
        }
    }

    return 0;
}

তাহলে প্রোগ্রাম ঠিকঠাকভাবে লিখে ওয়েবসাইটে গিয়ে জমা দাও।


সমস্যা ৩ – অধোগামী সংখ্যা

ইনপুট

প্রোগ্রামটিতে কোনো ইনপুট নেই।

আউটপুট

প্রতিটি লাইনে মোট পাঁচটি (5) করে সংখ্যা থাকবে এবং প্রতিটি সংখ্যা একটি \t (Tab) ক্যারেক্টার দিয়ে আলাদা করা থাকবে।

আউটপুট
1000999998997996
995994993992991
990989988987986
...
2019181716
1514131211
109876
54321
সমাধান দেখুন

সমাধান

এই সমস্যাটি তুলনামূলক একটি সহজ সমস্যা। এখানে 1000 থেকে 1 পর্যন্ত সংখ্যা প্রিন্ট করার কথা বলা হয়েছে। সমস্যার বর্ণনায় বলা আছে প্রোগ্রামটির কোনো ইনপুট নেই। এক্ষেত্রে আমাদের কাজ হলো শুধুমাত্র আউটপুট প্রিন্ট করা।

একটিমাত্র লুপ ব্যবহার করেই আমরা এই কোডটি করতে পারি। এক্ষেত্রে আমরা একটি for লুপের সাহায্য নিব। লুপটির মান শুরু হবে 1000 থেকে এবং এক এক করে কমে লুপটি 1 এ এসে থেমে যাবে। লুপটি হবে এমন:

for(int i = 1000; i >= 1; i--) { }

আমাদের এখানে i এর মান প্রিন্ট করতে হবে। এ জন্য আমরা printf() ফাংশন ব্যবহার করব। i এর মান প্রিন্ট করার সময় আমাদের খেয়াল রাখতে হবে দুটি বিষয়:

  1. আউটপুটে বলা আছে, প্রতি লাইনে 5 টি করে সংখ্যার কথা।
  2. প্রতিটি সংখ্যা একটি ট্যাব ক্যারেক্টার দিয়ে আলাদা করা থাকবে।

দ্বিতীয়ত, বলা আছে একটি ট্যাব ক্যারেক্টারের কথা। এখানে আমরা যখন i-এর মান প্রিন্ট করব তখন printf() ফাংশনটি লিখব এভাবে:

printf("%d\t", i);

এখন তোমরা কোডটি গুছিয়ে লিখে ফেলো। প্রথমে কম্পাইল ও রান করবে। তারপর সমস্যার লিঙ্কে গিয়ে সাবমিট করবে।

সমস্যা ৪ – ভাজক

ইনপুট

প্রথম লাইনে থাকবে টেস্ট কেসের সংখ্যা T (T <= 10)। এরপরে পরবর্তী T সংখ্যক লাইনে একটি করে পূর্ণ সংখ্যা N থাকবে, যেখানে 1 <= N <= 100000

আউটপুট

প্রতিটি কেসের জন্য একটি করে লাইন প্রিন্ট করতে হবে, শুরুতে কেস নম্বর দিতে হবে। এরপর N এর সব ধনাত্মক ছোট থেকে বড় আকারে প্রিন্ট করতে হবে এবং প্রতিটি ভাজক শুধুমাত্র একটি স্পেস দিয়ে আলাদা করতে হবে এবং লাইনের শেষে কোনো অতিরিক্ত স্পেস থাকবে না।

ইনপুটআউটপুট
3
6
15
23
Case 1: 1 2 3 6
Case 2: 1 3 5 15
Case 3: 1 23
সমাধান দেখুন

সমাধান

একটি সংখ্যার সবগুলো ধনাত্মক ভাজক বের করার সমস্যা এটি। আমরা জানি, কোনো একটি সংখ্যাকে যদি অপর অঋণাত্মক সংখ্যা দিয়ে নিঃশেষে ভাগ করা যায়, অর্থাৎ ভাগ করার পর ভাগশেষ শূন্য হয়, তাহলে ওই সংখ্যাগুলোকে সেই সংখ্যাটির ধনাত্মক ভাজক বলা হয়।

সমস্যাটির উদাহরণ ইনপুটের একটি সংখ্যা 6। 6 সংখ্যাটি 1, 2, 3 এবং 6 দ্বারা নিঃশেষে বিভাজ্য। তাই 1, 2, 3 এবং 6 হচ্ছে 6-এর ভাজক।

এবার আমরা কোড লেখার পালা। প্রথমে আমাদের প্রয়োজনীয় ভ্যারিয়েবল ডিক্লেয়ার করে নিব।

int T, i, n, j;

এখানে, T-টেস্ট কেসের জন্য। i-আমরা প্রতি লাইনে ইনপুট নেওয়ার জন্য যে লুপ ব্যবহার করব তার জন্য, N-আমরা যে সংখ্যাটির ভাজক বের করব তাই সেটির জন্য এবং j-ধনাত্মক বের করার জন্য আমাদের দ্বিতীয় আরেকটি লুপের দরকার হবে তার জন্য।

এবার আমাদের ইনপুট নেওয়ার পালা। যেহেতু, T সংখ্যক লাইনে ইনপুট নিতে হবে তাই প্রথমেই আমরা T-এর মান ইনপুট নিব।

scanf("%d", &T);

Case প্রিন্ট করার কাজটি আমরা N ইনপুট নেওয়ার পরেই লাইনেই করে ফেলব।

printf("Case %d:", i);

ধনাত্মক বের করার জন্য এখন আমরা আরেকটি লুপের সাহায্য নিব। লুপটি 1 থেকে শুরু করে N-এর মান পর্যন্ত চলবে (অবশ্যই N-এর সমানসহ)। N সংখ্যাটি 1 থেকে N পর্যন্ত যতগুলো সংখ্যা দিয়ে নিঃশেষে বিভাজ্য সেই সংখ্যাগুলো খুঁজে বের করে প্রিন্ট করতে হবে। বলা আছে ভাজকগুলো একটি স্পেস ক্যারেক্টার দিয়ে আলাদা থাকবে, তাই প্রিন্ট ফাংশনে একটি বাড়তি স্পেস ক্যারেক্টার দিতে হবে।

#include<stdio.h>

int main()
{
    int T, i, N, j;

    scanf("%d", &T);
    for(i = 1; i <= T; i++)
    {
        scanf("%d", &N);
        printf("Case %d:", i);
        for(j = 1; j <= N; j++)
        {
            if(N % j == 0)
            {
                printf(" %d", j);
            }
        }
        printf("\n");
    }

    return 0;
}

চিন্তা দিয়ে দেখ, কম্পিউটারকে দিয়ে 'a' আর 'A', দুটি আলাদা জিনিস। আরও একটি বিষয় বলে দেই, আমরা এখানে একটি লুপ ব্যবহার করে ভাজক বের করেছি। তোমরা সমস্যার বিবরণ পড়লে দেখতে পাবে, N এর মান সর্বোচ্চ 100000 পর্যন্ত হতে পারে। অর্থাৎ, তখন আমাদের এই লুপটি 100000 বার পর্যন্ত চলবে। আমরা একটু চিন্তা করে দেখি তো, এর চেয়ে কম সংখ্যক বার লুপটি চালিয়ে কি এই সমাধানটি করা যেত? একটি সংখ্যার যতগুলো ভাজক আছে সাধারণত তার অর্ধেক সংখ্যক ভাজক তার বর্ণমালার চেয়ে ছোট, আর বাকি অর্ধেক তার বর্ণমালার চেয়ে বড়।

সমস্যা ৫ – বাক্স ১

ইনপুট

প্রথম লাইনে একটি সংখ্যা T (1<=T<=25) থাকবে এবং তারপরে T-সংখ্যক লাইন থাকবে। প্রতিটি লাইনে প্রত্যেকটি করে সংখ্যা (N) থাকবে যার মান 1 থেকে 80-এর মধ্যে হবে।

আউটপুট

প্রতিটি N-এর জন্য NxN বর্গ আঁকতে হবে। বর্গটি * দিয়ে পূর্ণ করতে হবে। প্রতিটি বর্গ একটি ফাঁকা লাইন দিয়ে পৃথক করা দিতে হবে। পৃথক করার কাজে ব্যবহৃত অন্য কোনো অতিরিক্ত ফাঁকা লাইন বা স্পেস রাখা যাবে না।

ইনপুটআউটপুট
3
1
3
5
*

***
***
***

*****
*****
*****
*****
*****
সমাধান দেখুন

সমাধান

সমস্যাটি বেশ মজার। * অক্ষর ব্যবহার করে বাক্স বানানো, তাও আবার প্রোগ্রামিংয়ের সাহায্যে। এই প্রোগ্রামটিতে * অক্ষর ব্যবহার করে একটি চারকোণা বাক্স আউটপুটে দেখাতে হবে।

এখানে একটি লুপ ব্যবহার করা যাবে না। আমাদের নেস্টেড লুপ ব্যবহার করব। প্রোগ্রামিংয়ের ভাষায় আমরা একে বলি নেস্টেড লুপ। বলা আছে, NxN মানে লম্বালম্বি এবং আড়াআড়ি দিকেই N সংখ্যক * থাকবে।

নেস্টেড for লুপের গঠনটা এমন:

outer loop()
{
    inner loop()
    {
        // necessary code;
    }
}

outer এবং inner লুপের জন্য আলাদা আলাদা ভ্যারিয়েবল ডিক্লেয়ার করতে হবে।

int i, j;

প্রতিটি লুপ N এর মান যত ঠিক ততবার করে চলবে এবং * প্রিন্ট করবে। এছাড়া প্রতিটি কেসের সংখ্যা ইনপুট নেওয়ার জন্য আমাদের আরেকটি লুপের দরকার পড়বে। ঠিকমতো কোড লিখতে পারলে তোমরা বাক্স-১ সমস্যাটির সমাধান করতে পারবে। কোড লেখার সময় আউটপুটের বর্ণনা ভালো করে পড়ে নিতে হবে।


সমস্যা ৬ – যোগফল নির্ণয়

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=10000), যা মোট কতটি পাঁচ অঙ্কের সংখ্যা ইনপুট হবে তা নির্দেশ করবে। পরবর্তীতে T সংখ্যক লাইনে একটি করে পূর্ণসংখ্যা N (0<=N<=65535) ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে N এর প্রথম এবং শেষ অঙ্কের যোগফল প্রিন্ট করতে হবে নিচের ছকে যেভাবে দেখানো আছে ঠিক সেই ফরম্যাটে। প্রতিটি আউটপুটের পরে একটি নিউলাইন প্রিন্ট করতে হবে। আউটপুটে "=" এর আগে এবং পরের স্পেসটি লক্ষণীয়।

ইনপুটআউটপুট
5
12345
56789
14310
10062
96587
Sum = 6
Sum = 14
Sum = 1
Sum = 3
Sum = 16
সমাধান দেখুন

সমাধান

তোমরা সবাই নিশ্চয়ই সংখ্যা ও অঙ্কের পার্থক্য জানো? 162 একটি সংখ্যা যার এককের ঘরের অঙ্কটি হচ্ছে 2, দশকের ঘরের অঙ্কটি হচ্ছে 6 আর শতকের ঘরের অঙ্কটি হচ্ছে 1। আর প্রথম ও শেষ অঙ্ক বলতে কী বোঝানো হচ্ছে? গণিতের ভাষায় প্রথম অঙ্ক বলতে বোঝায় তার সর্ববামের অঙ্কটি, যাকে ইংরেজিতে বলে Most Significant Digit (MSD)। আর শেষ অঙ্ক বলতে বোঝায় সর্বডানের অঙ্কটি এককের ঘরের অঙ্ক, যাকে ইংরেজিতে বলে Least Significant Digit (LSD)।

সমস্যার বর্ণনায় বলা আছে পাঁচ অঙ্কের একটি সংখ্যার প্রথম এবং শেষ অঙ্কের যোগফল বের করতে হবে। উদাহরণস্বরূপ আমরা নমুনা আউটপুটের সংখ্যা 12345 বিবেচনায় আনি। খেয়াল করে দেখো, আমরা যদি এই সংখ্যাটিকে 10 দিয়ে ভাগ করি তাহলে আমাদের ভাগশেষ থাকবে 5, যা সংখ্যাটির সর্বশেষ অঙ্ক (LSD)। তাহলে আমরা আমাদের সংখ্যাটির শেষ অঙ্কটি পেয়ে গেলাম। এবার আমাদের সংখ্যাটির প্রথম অঙ্কটি বের করার পালা। দেখি সেটি কীভাবে করা যায়।

12345-কে 10 দিয়ে ভাগ করলে ভাগফল হচ্ছে 1234 আর ভাগশেষ 5।
1234-কে 10 দিয়ে ভাগ করলে ভাগফল 123 আর ভাগশেষ 4।
123-কে 10 দিয়ে ভাগ করলে ভাগফল 12 আর ভাগশেষ 3।
12-কে 10 দিয়ে ভাগ করলে ভাগফল 1 আর ভাগশেষ 2।
1-কে 10 দিয়ে ভাগ করলে ভাগফল 0 আর ভাগশেষ 1।

যখনই আমাদের ভাগফল 0 হবে, তখন ভাগশেষ যে সংখ্যাটি থাকবে, সেটি এক অঙ্কের সংখ্যা (যেহেতু 10 দিয়ে ভাগ করা হচ্ছে) আর সেটিই হচ্ছে আমাদের কাঙ্ক্ষিত প্রথম অঙ্ক (MSD)।

তাহলে আমরা প্রোগ্রাম লিখব কীভাবে? একটি int ভ্যারিয়েবলে পাঁচ অঙ্কের সংখ্যাটি ইনপুট নেব (ধরা যাক, N), তারপর 10 দিয়ে মড (মডুলাস অপারেটর, %) করে ভাগশেষ বের করব, যেটি হচ্ছে সংখ্যাটির শেষ অঙ্ক বা LSD। তারপর যেকোনো একটি লুপের সাহায্যে (for কিংবা while) সংখ্যাটি 10 দিয়ে মড (%) করে ভাগশেষ বের করব এবং সংখ্যাটিকে 10 দিয়ে ভাগ করব। সবশেষে ভাগফলটি আবার ওই ভ্যারিয়েবলে অ্যাসাইন করব। যখন, ভাগফল শূন্য হয়ে যাবে, তখন লুপ থেকে বের হয়ে আসব আর শেষ যেই ভাগশেষ পেয়েছিলাম, সেটিই হচ্ছে প্রথম অঙ্ক বা MSD। তবে যেহেতু এখানে নির্দিষ্ট করে ঠিক 5 টি অঙ্কের কথা বলা হয়েছে, তাই লুপ ব্যবহার না করেও এই সমস্যাটি সমাধান করা যাবে। সেটি কীভাবে তা তোমরা একটু চিন্তা করে বের করতে হবে।

দুটি অঙ্ক বের করার পরের কাজটি খুবই সহজ। এবার সংখ্যা দুটি যোগ করে আউটপুট প্রিন্ট করে ফেলো।

সমস্যা ৭ – সংখ্যা গণনা

ইনপুট

প্রথম লাইনে একটি সংখ্যা T (1<=T<=100) থাকবে। তারপর T-এর মান যত, ততটি লাইন থাকবে। প্রতিটি লাইনে এক বা একাধিক সংখ্যা থাকবে যাদের পরিমাণ 10000000-এর বেশি হবে না। একটি লাইনের সংখ্যাগুলোর মধ্যে এক বা একাধিক স্পেস ক্যারেক্টার থাকবে।

আউটপুট

প্রতিটি লাইনে কয়টি সংখ্যা আছে সেটি প্রিন্ট করতে হবে।

ইনপুটআউটপুট
4
1 -2 10000 -50 20 7 445
9
-98 876 65
223 9876452 212
7
1
3
3
সমাধান দেখুন

সমাধান

এই সমস্যাটি সমাধান করার জন্য আমরা strtol() নামে একটি ফাংশন ব্যবহার করব। এই ফাংশনকে বলা হয় string to long কনভার্টার, অর্থাৎ, এই ফাংশনকে কোনো সংখ্যা স্ট্রিং ডেটা টাইপে ইনপুট দিলে সে, Long ডেটা টাইপে সেই সংখ্যাটি রিটার্ন করে। আর এই ফাংশনটি রয়েছে stdlib.h হেডার ফাইলে। চলো আমরা প্রথমে দেখে নিই এই ফাংশনটি কীভাবে ব্যবহার করা যায়।

#include<stdio.h>
#include<stdlib.h>

int main()
{
    char line[] = "1 -2 10000 -50 20 7 445";
    char *p, *e;
    long input;
    int count = 0;
    p = line;

    for (p = line; ; p = e)
    {
        input = strtol(p, &e, 10);
        if (p == e)
            break;
        count++;
    }
    printf("%d\n", count);

    return 0;
}

তোমরা প্রথমেই এই কোডটি নিজেদের কম্পিউটারে চালিয়ে দেখ এটি কেমন আউটপুট দেয়। দেখবে এটি ঠিক 7 সংখ্যাটি প্রিন্ট করে। দেখ আমাদের line নামক স্ট্রিংটিতে কিন্তু ঠিক 7টি পূর্ণসংখ্যা রয়েছে। লক্ষ করো, আমরা stdlib.h হেডার ফাইলটি শুরুতেই ইনক্লুড করে নিয়েছি।

পয়েন্টার বিষয়ে ধারণা নেই তাদেরে আগে এই দুটি বিষয়ে ধারণা পরিষ্কার করে নিতে হবে। আর এই strtol() ফাংশনের বিস্তারিত বর্ণনা পাবে এখানে: http://www.cplusplus.com/reference/cstdlib/strtol/

তাহলে তো দেখে ফেললে একটি স্ট্রিং থেকে কীভাবে তাতে কয়টি সংখ্যা আছে বের করে ফেলা যায়। এখন আমাদের কাজ হচ্ছে এই স্ট্রিংটি ইনপুট নেওয়া। যেহেতু এখানে স্ট্রিংয়ের দৈর্ঘ্য কত হতে পারে তা বলা নেই তাই আমরা ধরে নেব এর দৈর্ঘ্য 100000।

char line[100000];
scanf("%[^\n]", line);

খেয়াল করো আমরা কিন্তু %s ব্যবহার করে ইনপুট নেইনি। এভাবে ইনপুট নেওয়া হলে সেটি পরের অন্য একটি সমস্যার সমাধান ব্যাখ্যায় বলা হয়েছে। তাহলে এখন তোমরা পুরো কোডটি গুছিয়ে লিখে ফেলো আর লিঙ্কে গিয়ে সাবমিট করে দাও। যদি রানটাইম এরর আসে, তাহলে বুঝতে হবে স্ট্রিংয়ের দৈর্ঘ্য আরও বেশি হতে পারে। তখন স্ট্রিংয়ের দৈর্ঘ্য বাড়িয়ে আবার সাবমিট করতে হবে।

সমস্যা ৮ – ছোট থেকে বড়

ইনপুট

ইনপুটের প্রথম লাইনে থাকবে টেস্ট কেসের সংখ্যা T (T<=100)। এরপরে T সংখ্যক লাইন থাকবে। প্রতিটি লাইনে তিনটি করে পূর্ণসংখ্যা n1, n2, n3 থাকবে যাদের প্রত্যেকে স্বতন্ত্র (অর্থাৎ, কোনো দুটি সংখ্যা পরস্পর সমান নয়) এবং 1000 এর সমান বা ছোট।

আউটপুট

প্রতিটি কেসের জন্য একটি করে কেস নম্বর প্রিন্ট করতে হবে। এরপর প্রদত্ত তিনটি সংখ্যাকে ছোট থেকে বড় আকারে সাজিয়ে প্রিন্ট করতে হবে। পাশাপাশি দুটি সংখ্যার মধ্যে শুধুমাত্র একটি স্পেস প্রিন্ট করতে হবে। নমুনা আউটপুটটি আরও বিস্তারিত দেখতে পারো।

ইনপুটআউটপুট
3
3 2 1
1 2 3
10 5 6
Case 1: 1 2 3
Case 2: 1 2 3
Case 3: 5 6 10
সমাধান দেখুন

সমাধান

তোমরা যারা ইতিমধ্যেই বিভিন্ন প্রকার সর্টিংয়ের সঙ্গে পরিচিত, যেমন বাবল সর্ট, সিলেকশন সর্ট ইত্যাদি, তারা চাইলেই যেকোনো সর্টিং অ্যালগরিদম ব্যবহার করে সমস্যাটির সমাধান করতে পারো। সর্টিং মানে হচ্ছে ক্রমানুসারে সাজানো (ছোট থেকে বড় কিংবা বড় থেকে ছোট)। আর এই সমস্যার সমাধানে সেই কাজটিই করতে হবে। কিন্তু আমি চাই তোমরা কোনো অ্যালগরিদম ব্যবহার না করে সমস্যাটির সমাধান করো। কীভাবে? সবচেয়ে ভালো হয় নিজে কিছু চিন্তা করে সমাধান বের করতে পারলে। চেষ্টা করে না পারলে (কিংবা পারলেও) নিচের অংশটুকু পড়ো।

এই সমস্যায় তোমাদের যদি তিনটি সংখ্যার পরিবর্তে দুটি সংখ্যা দেওয়া হতো এবং সেগুলোকে ছোট-বড় ক্রমানুসারে সাজাতে বলা হতো, তাহলে তোমরা কী করতে? আমি পুরো কোডটি লিখে দিচ্ছি, তোমরা সহজেই বুঝতে পারবে।

int main()
{
    int T, n1, n2, temp, kase;
    scanf("%d", &T);
    for(kase = 1; kase <= T; kase++)
    {
        scanf("%d %d", &n1, &n2);
        if (n1 > n2)
        {
            temp = n1;
            n1 = n2;
            n2 = temp;
        }
        printf("Case %d: %d %d\n", kase, n1, n2);
    }
    return 0;
}

লজিক খুবই সহজ, প্রথম সংখ্যাটি যদি দ্বিতীয় সংখ্যার চেয়ে বড় হয়, তাহলে সংখ্যা দুটি अदল-বদল করে ফেললেই হয়! তাহলে তিনটি সংখ্যা থাকলে কী করতে হবে, সেটি নিশ্চয়ই বুঝতে পারছ। মোট তিনবার अदল-বদল করতে হবে। সেটি তোমরা নিজেরা করে ফেলো।

আরেকটি ব্যাপার লক্ষ কর। আমি ভ্যারিয়েবল ডিক্লেয়ার করার সময় kase নাম দিয়েছি, case দিইনি। কারণ কী? কারণ case হচ্ছে সি ভাষায় একটি সংরক্ষিত একটি শব্দ (reserved keyword)। তাই এই নামে কোনো ভ্যারিয়েবলের নামকরণ করা যাবে না, ফাংশনের নামেও এসব শব্দ ব্যবহার করা যাবে না। সি ভাষায় অন্যান্য সংরক্ষিত শব্দগুলো হচ্ছে:

autoelselongswitch
breakenumregistertypedef
caseexternreturnunion
charfloatshortunsigned
constforsignedvoid
continuegotosizeofvolatile
defaultifstaticwhile
dointstruct_Packed
double

সমস্যা ৯ – পূর্ণবর্গ সংখ্যা

ইনপুট

ইনপুটের প্রথম লাইনে থাকবে টেস্ট কেসের সংখ্যা T (T<=100)। এরপরে T সংখ্যক লাইন থাকবে। প্রতিটি লাইনে থাকবে একটি পূর্ণসংখ্যা N (0<=N<=2³¹-1)

আউটপুট

প্রোগ্রামটির আউটপুটে N পূর্ণবর্গ সংখ্যা হলে YES প্রিন্ট করতে হবে। অন্যথায় প্রিন্ট করতে হবে NO

ইনপুটআউটপুট
3
16
18
196
YES
NO
YES
সমাধান দেখুন

সমাধান

পূর্ণবর্গ সংখ্যা হচ্ছে সেসব সংখ্যা, যেসব সংখ্যার বর্গমূল একটি পূর্ণসংখ্যা। তাহলে এই সমস্যার সমাধান করতে গিয়ে আমাদের প্রথমে যে কাজটি করতে হবে, তা হলো বর্গমূল বের করা। তারপর সেই বর্গমূলটি পূর্ণ সংখ্যা কি না, তা যাচাই করা। বর্গমূল নির্ণয় করার জন্য math.h হেডার ফাইলে sqrt() ফাংশন রয়েছে। আর পূর্ণসংখ্যা কি না, তা যাচাই করার বেশ কয়েকটি উপায় রয়েছে।

double sq_root = sqrt(num);
if (ceil(sq_root) == floor(sq_root))
{
    printf("YES");
}
else

এই সমাধানটিতে আমরা ceil()floor() নামে দুটি ফাংশন ব্যবহার করেছি। ceil() ফাংশন একটি বাস্তব সংখ্যা ইনপুট নেয় এবং সেই সংখ্যার চেয়ে সর্বনিম্ন পূর্ণসংখ্যা রিটার্ন করে। যেমন ceil(2.1) লিখলে, সেটি রিটার্ন করবে 3.0, ceil(2.8) লিখলেও সেটি 3.0 রিটার্ন করবে। floor() ফাংশন একটি বাস্তব সংখ্যা ইনপুট নেয় এবং সেই সংখ্যার চেয়ে সর্বোচ্চ পূর্ণসংখ্যা রিটার্ন করে। floor(2.1) রিটার্ন করবে 2.0। একইভাবে floor(2.8) রিটার্ন করবে 2.0। আমরা এখানে যে যুক্তি ব্যবহার করেছি তা হলো, বর্গমূল sq_root যদি পূর্ণসংখ্যা হয়, তবে তার ceil() এবং floor() এর মান সমান হবে। আর যদি না হয়, বিষয়টি তোমরা বুঝতে পারছ।

তবে এই সমাধানে ছোট একটি সমস্যা রয়েছে। ceil()floor() দুটি ফাংশনই রিটার্ন টাইপ হচ্ছে double বা float। দুটি double বা float টাইপের ভ্যারিয়েবল == দিয়ে তুলনা করলে অনেক সময় ভুল হয়। এটি প্রোগ্রামিংয়ের দোষ নয়, কম্পিউটারের প্রসেসরের দোষ। তো তোমার কী করার আছে? তুমি কোড এভাবে লিখতে পারো:

double sq_root = sqrt(num);
double difference = ceil(sq_root) - floor(sq_root);

if (difference < 0.000001)
{
    printf("YES\n");
}
else
{
    printf("NO\n");
}

তবে আমি এই সমস্যার সমাধানের জন্য একটি পদ্ধতি বের করে নেব। সেটিও কোড দেখলেই তোমরা বুঝতে পারবে। শুধু বলে দিই যেকোনো double ভ্যারিয়েবলকে int ভ্যারিয়েবলে অ্যাসাইন করলে আপনাআপনি টাইপকাস্ট হয়ে যায়। টাইপকাস্ট কী জিনিস সেটি না জানলে কোনো বই পড়ে বা গুগলে জিজ্ঞাসা করে জেনে নাও। অথবা প্রশ্ন করতে পারো http://programabad.com -এ।

আরেকটি সহজ সমাধান হতে পারে এমন:

int num, sq_root;
scanf("%d", &num);
sq_root = sqrt(num);
if (sq_root * sq_root == num)
{
    printf("YES\n");
}
else
{
    printf("NO\n");
}

সমস্যা ১০ – রান রেট

ইনপুট

প্রথম লাইনে একটি সংখ্যা T (1<=T<=100) থাকবে। ওই সংখ্যার মান যত, এর পরে ততগুলো লাইনে তিনটি করে সংখ্যা থাকবে। প্রথম সংখ্যাটি প্রতিপক্ষের মোট রান, r1 (1<=r1<=1000), দ্বিতীয় সংখ্যাটি ব্যাটসম্যানদের বর্তমান রান, r2 (1<=r2<=r1) এবং তৃতীয় সংখ্যাটি খেলার আর কত বল বাকি আছে, B (1<=B<=300) তা নির্দেশ করে।

আউটপুট

প্রতি লাইনের জন্য সেই লাইনের দেওয়া তথ্য থেকে হিসাব করে প্রথমে বর্তমান রানরেট এবং এরপর একটি স্পেস দিয়ে কাঙ্ক্ষিত রানরেট প্রিন্ট করতে হবে। প্রতিটি হার অবশ্যই দশমিকের পরে শুধুমাত্র দুই অঙ্ক পর্যন্ত দেখাতে হবে।

ইনপুটআউটপুট
4
300 294 6
200 100 100
333 250 40
118 100 180
6.00 7.00
3.00 6.06
5.77 12.60
5.00 0.63
সমাধান দেখুন

সমাধান

তোমরা নিশ্চয়ই ক্রিকেট খেলা বোঝ, অন্তত আমার চাইতে তো বেশি অবশ্যই। তো এই সমস্যাটি সমাধান করার সময় ভুলে গেলে চলবে না যে প্রতিপক্ষের রান যদি 300 হয়, তাহলে দ্বিতীয় ইনিংসে যারা ব্যাট করছে, তাদের জয়ের জন্য 301 রান করতে হবে। তাহলে কথা বাড়িয়ে লাভ নেই, সরাসরি কোডে চলে যাই (হ্যাঁ, পুরো কোডটি লিখে দিচ্ছি):

#include<stdio.h>

int main()
{
    int T, r1, r2, B;
    double current_rr, asking_rr; // Run Rates

    scanf("%d", &T);
    while(T--)
    {
        scanf("%d %d %d", &r1, &r2, &B);
        current_rr = (r2 / ((300.0 - B) / 6.0));
        asking_rr = ((r1 - r2 + 1.0) / B) * 6.0;
        printf("%.2lf %.2lf\n", current_rr, asking_rr);
    }
    return 0;
}

তোমরা কোডটি একবার পড়লেই বুঝতে পারবে। অনেক সহজ। কিন্তু প্রোগ্রাম যখন রান করবে, দেখবে যে উদাহরণে যে ইনপুট আছে, সেগুলোর জন্য তোমার আউটপুট উদাহরণের আউটপুটের সঙ্গে মিলছে না!

কারণ হচ্ছে কম্পিউটার প্রোগ্রামে আমরা যখন পূর্ণসংখ্যাকে পূর্ণসংখ্যা দিয়ে ভাগ করি, ভাগফলও আসে পূর্ণসংখ্যা। তাই আমরা ভাগফলটি কোনো double টাইপের ভ্যারিয়েবলে রাখলেও সেখানে ওই পূর্ণসংখ্যাই আসে। একটি ছোট প্রোগ্রাম লিখে দেখা যাক:

int main()
{
    int num1 = 5, num2 = 2;
    double ans;
    ans = num1 / num2;
    printf("ans = %.2lf\n", ans);
    return 0;
}

আউটপুট কী পাচ্ছি? ans = 2.00। তাই আমাদের যেটি করতে হবে, ভাগ করার আগেই ইন্টিজারকে double টাইপে নিয়ে যেতে হবে। সহজ বুদ্ধি হচ্ছে ইন্টিজারকে 1.0 দিয়ে গুণ করা। যেমন:

ans = num1 * 1.0 / num2;

তাহলে আউটপুট আসবে ans = 2.50 যা আমাদের প্রত্যাশিত আউটপুট। তাহলে তোমরা প্রোগ্রামটি ঠিকঠাক করে লিখে ফেলো।

সমস্যা ১১ – মৌলিক বা ফ্যাক্টরিয়াল

ইনপুট

ইনপুটের প্রথম লাইনে থাকবে টেস্ট কেসের সংখ্যা T (T<=100)। এরপরে T সংখ্যক লাইন থাকবে। প্রতিটি লাইনে থাকবে একটি পূর্ণসংখ্যা N (0<=N<=15)

আউটপুট

প্রোগ্রামটির আউটপুটে মৌলিক বা ফ্যাক্টরিয়াল প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
6
10
15
720
3628800
1307674368000
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় বলা আছে প্রথমে একটি সংখ্যা T থাকবে এবং তারপরে T সংখ্যক লাইনে একটি পূর্ণসংখ্যা ইনপুট নিতে হবে। তাহলে প্রথমেই আমাদের T এর মান ইনপুট নিতে হবে। এখানে আমরা T-এর ডেটা টাইপ হিসেবে int ব্যবহার করব।

আমাদের ফ্যাক্টরিয়াল বা মৌলিকের কাজের জন্য কোড লেখার পালা। ফ্যাক্টরিয়ালের কোড আমরা রিকার্শন (recursion) ব্যবহার করে করতে পারি, কিন্তু সেক্ষেত্রে আমাদের রানটাইম লেগে যাবে অনেক বেশি। তাই আমরা এখানে ফ্যাক্টরিয়াল काढার জন্য লুপের সাহায্য করব।

ফ্যাক্টরিয়ালের ধারণাটি আসলে কী? আমরা জানি, কোনো সংখ্যার ফ্যাক্টরিয়াল সেই সংখ্যাসহ তার আগের সংখ্যাগুলোর গুণফল। যেমন: 5 এর ফ্যাক্টরিয়াল 120 (1×2×3×4×5 = 120)। এই কাজটি করার জন্য আমাদের 1 থেকে N পর্যন্ত সংখ্যাগুলোর গুণফল বের করতে হবে।

N-এর ফ্যাক্টরিয়ালের মান গণনা করার জন্য আমরা আরেকটি ভ্যারিয়েবল ব্যবহার করব। লক্ষ করে দেখ, 15 এর ফ্যাক্টরিয়াল বা মৌলিক বেশ বড় একটি সংখ্যা। তাই এখানে ফ্যাক্টরিয়াল এর জন্য আমরা long long int ডেটা টাইপ ব্যবহার করব। প্রথমে আমরা এই ভ্যারিয়েবলের মান রাখব 1 অর্থাৎ factorial = 1;। এবং N পর্যন্ত for লুপ দিয়ে N এর ফ্যাক্টরিয়াল এর মান বের করব। ফ্যাক্টরিয়ালের জন্য আমাদের কোডটি হবে এমন:

long long int factorial = 1, i;
for(i = 2; i <= N; i++)
{
    factorial = factorial * i;
}

এখানে, factorial = factorial*i; এই statement এ প্রতিবার factorial এর মানের সঙ্গে i এর মান গুণ হয়ে N পর্যন্ত যা আমাদের কাঙ্ক্ষিত আউটপুট। আরও একটি ব্যাপার লক্ষ করো, আমরা i এর মান 1 না দিয়ে শুরু করে 2 দিয়ে শুরু করেছি, কারণ 1×1=1 তাই, 1 দিয়ে আলাদাভাবে গুণ করার দরকার নেই। আমাদের আউটপুট statement-টি হবে এমন:

printf("%lld\n", factorial);

প্রতিবার আউটপুট প্রিন্ট শেষে একটি নিউলাইন অবশ্যই প্রিন্ট করতে হবে। এবার তোমাদের কাজ হচ্ছে গুছিয়ে সুন্দরভাবে কোডটি লিখে ফেলা।


সমস্যা ১২ – ফ্যাক্টরিয়াল ১০০

ইনপুট

ইনপুটের প্রথম লাইনে থাকবে টেস্ট কেসের সংখ্যা T (T<=100)। এরপরে T সংখ্যক লাইন থাকবে। প্রতিটি লাইনে থাকবে একটি পূর্ণসংখ্যা N (0<=N<=100)

আউটপুট

N ফ্যাক্টরিয়ালের শেষে কয়টি শূন্য (0) আছে, তা এক লাইনে প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
6
15
100
1
3
24
সমাধান দেখুন

সমাধান

N-এর ফ্যাক্টরিয়ালে যেই সংখ্যাটি, তার শেষে মোট কয়টি 0 আছে, সেটি আমাদের বের করতে হবে। শুরুতেই আমরা দেখি, একটি সংখ্যার শেষে কয়টি 0 আছে, সেটি কীভাবে বের করা যায়।

কোনো সংখ্যাকে 10 দিয়ে ভাগ করলে ভাগশেষ হবে 0 থেকে 9 পর্যন্ত যেকোনো সংখ্যা। 10 দিয়ে ভাগ করলে ভাগশেষ 0 তখনই হবে, যখন সংখ্যাটির সবচেয়ে ডানদিকের অঙ্ক (এককের ঘরের অঙ্ক বা LSD) 0 হবে। একটি উদাহরণ দেওয়া যাক। 3100-এর শেষে কয়টি 0 আছে? প্রথমে 3100 % 10 এর মান হবে 0। তার মানে সবচেয়ে ডানদিকের 0 পেয়ে গেলাম। তারপর 3100 কে 10 দিয়ে ভাগ দিই (3100 / 10), তাহলে হয় 310। অর্থাৎ 310-কে আবার 10 দিয়ে মড করি, ভাগশেষ 0। তাহলে এখন পর্যন্ত ডানদিকে দুটি 0 পেলাম। তারপর 310-কে 10 দিয়ে ভাগ করি, ভাগফল 31। 31-কে আবার 10 দিয়ে মড করি, ফলাফল 1। এখানেই আমাদের থেমে যেতে হবে। আমরা যতক্ষণ ভাগশেষ 0 পাচ্ছিলাম ততক্ষণ একই কাজের পুনরাবৃত্তি করছিলাম।

3100 % 10 = 03100 / 10 = 310
310 % 10 = 0310 / 10 = 31
31 % 10 = 1stop

প্রোগ্রামিংয়ে কাজটি লুপ দিয়ে করতে হবে, অথবা নিশ্চয়ই তোমরা সবাই বুঝে ফেলেছ।

int mod, zero_count = 0;
while(number > 0)
{
    mod = number % 10;
    if (mod == 0)
        zero_count++;
    else
        break;
    number = number / 10;
}

এখন তোমরা ভাবছ, সমস্যার সমাধান তো হয়েই গেল। N-এর ফ্যাক্টরিয়াল বের করে শেষে কয়টি 0 আছে, তা ওপরের কোড ব্যবহার করেই বের করে ফেলা যাবে। কিন্তু ঘাপলা হচ্ছে N-এর মান 100 পর্যন্ত হতে পারে, আর 100! সংখ্যাটি এত বড় সংখ্যা যে int, এমনকি long long int ব্যবহার করেও সংখ্যাটি রাখা যাবে না। তাহলে কি স্ট্রিং ব্যবহার করব?

স্ট্রিং ব্যবহার করে চেষ্টা করতে পারো, কিন্তু এত কষ্ট না করলেও চলবে। আসলে 100!-এর শেষে কয়টি 0 আছে, সেটি বের করার জন্য 100!-এর পুরো মান আমাদের বের করার দরকার নেই। একটি সংখ্যার শেষে একটি 0 কখন আসে? যখন সেটির একটি উৎপাদক 10 হয়। যেমন : 500 = 50×10 = 5×10×10। তার মানে দুটি 10 আছে, তাই সংখ্যাটির শেষেও দুটি 0।

আবার 10 কীভাবে তৈরি হয়? 10 = 5×2। 5 ও 2, উভয়ই মৌলিক সংখ্যা, তাই এদেরকে আর উৎপাদকে ভাঙা যাবে না।

অর্থাৎ,

10! = 10 x 9 x 8 x 7 x 6 x 5 x 4 x 3 x 2 x 1

= (5x2) x (3x3) x (2x2x2) x 7 x (3x2) x 5 x (2x2) x 3 x 2 x 1

= 7 x (5x5) x (3x3x3x3) x (2x2x2x2x2x2x2x2) x 1

এখানে 5 আছে দুটি, আর 2 তো এর চেয়ে অনেক বেশি আছে (7টি)। আর 5-এর সঙ্গে 2 গুণ করলেই 10 তৈরি হয়। তাই এখানে শূন্য তৈরি হবে 2 বার (আর সেগুলোর জন্য যথেষ্ট 2 আছে), তাই সবার শেষে শূন্যও থাকবে 2টি। তোমরা 10! এর মান বের করে দেখতে পারো।

আর যদি 3628800। ডানদিকে দুটি 0। আমরা কিন্তু এই মান বের না করেই সেটি বলে দিতে পেরেছি।

আর কোড করে দেব না। তোমরা এখন নিজেরা চেষ্টা করে কোড লিখে ফেলো।

সমস্যা ১৩ – টম মিয়ার প্রোবাবিলিটি

ইনপুট

প্রথম লাইনে একটি পূর্ণসংখ্যা T (1<=T<=100) থাকবে। পরবর্তীতে T সংখ্যক লাইন থাকবে এবং প্রতি লাইনে একটি ইংরেজি বাক্য থাকবে – সেখানে 10টির বেশি শব্দ থাকবে না। প্রতি শব্দে 20টির বেশি বর্ণ (Letter) থাকবে না।

আউটপুট

প্রতি লাইনে অনুবাদ সঠিক হওয়ার প্রোবাবিলিটি প্রিন্ট করতে হবে। তুমি ধরে নিতে পারো, প্রতিটি বাক্যের জন্য শুধু একটি সঠিক অনুবাদ আছে। অনুক্রম মানে হচ্ছে order। আউটপুট দেখাতে হবে 1/n আকারে যেখানে n একটি পূর্ণসংখ্যা।

ইনপুটআউটপুট
2
eat you rice
no way no good
1/6
1/12
সমাধান দেখুন

সমাধান

সমস্যাটি পড়ে ঘাবড়ানোর কিছু নেই। তোমাদের যদি বিন্যাস-সমাবেশ জানা থাকে, তাহলে সমাধান খুবই সহজ। না জানা থাকলে কলেজ লেভেলে বই কারো কাছে চেয়ে নাও, বা নিজেও উচ্চ মাধ্যমিক গণিত বই সংগ্রহ করে পড়ে নিতে পারো।

n-সংখ্যক জিনিসকে সাজানো যায় n! উপায়ে। আবার জিনিসগুলোর মধ্যে যদি n₁ সংখ্যক জিনিস একই রকম হয়, আর n₂ সংখ্যক জিনিস একই রকম হয়, তখন একটু ঝামেলা বেঁধে যায়। ধরা যাক বিভিন্ন রঙের 10টি বল আছে, এখন 3টি বল যদি একই রঙের হয়, ধরা যাক নীল, তাহলে কত কত উপায়ে বলগুলো সাজানো যাবে? আবার যদি 3টি নীল বল, 2টি সাদা বল, 4টি লাল বল আর 1টি সবুজ বল হয়, তাহলে বলগুলো কত উপায়ে সাজানো যায়?

তোমরা বই থেকে সূত্র দেখে প্রোগ্রাম লিখে ফেলো না যেন। ভালোভাবে পড়াশোনা ও একটু চিন্তাভাবনা করো।

আরেকটি বিষয় হচ্ছে হিসাব-নিকাশে যাওয়ার আগে, কোন শব্দ কতবার আছে, সেটি গণনা করতে হবে। এটি মোটেও কঠিন কোনো কাজ নয়, যদি তোমরা “শব্দ গণনা – ২” সমস্যাটি সমাধান করে থাকো।

সমস্যা ১৪ – অক্ষরের ঘনঘটা

ইনপুট

প্রথম লাইনে একটি পূর্ণসংখ্যা T (1<=T<=100) থাকবে। পরবর্তীতে 2xT সংখ্যক লাইন থাকবে। পরবর্তী প্রতি জোড়াজোড়া লাইনের প্রথমটিতে একটি স্ট্রিং (string) থাকবে যার দৈর্ঘ্য সর্বোচ্চ 10000 এবং দ্বিতীয় লাইনে একটি ক্যারেক্টার (character) থাকবে।

আউটপুট

প্রোগ্রামটির আউটপুটে ক্যারেক্টারটি স্ট্রিংয়ে কতবার আছে সেটি প্রিন্ট করতে হবে নিম্নরূপে।

ইনপুটআউটপুট
2
hello world
l
hello world
a
Occurrence of 'l' in 'hello world' = 3
'a' is not present
সমাধান দেখুন

সমাধান

এই সমস্যার বর্ণনায় বলা আছে যে প্রতিটি কেসে ইনপুট দেওয়া হবে দুটি লাইন। প্রথম লাইনে একটি স্ট্রিং ও দ্বিতীয় লাইনে একটি ক্যারেক্টার। তাই প্রথম লাইনটি ইনপুট নেওয়ার জন্য আমরা একটি স্ট্রিং অর্থাৎ ক্যারেক্টার অ্যারে ব্যবহার করব। আর দ্বিতীয় লাইনটি ইনপুট নেওয়ার জন্য একটি ক্যারেক্টার ব্যবহার করলেই হয়, আবার একটি স্ট্রিংও ব্যবহার করা যায়।

char first_line[10001];
char second_line[2];

দ্বিতীয় লাইনে আমি স্ট্রিং ব্যবহার করেছি এবং এর দৈর্ঘ্য 2 করে দিয়েছি। কারণ একটি ক্যারেক্টার ইনপুট হলে সেটির জন্য একঘর ব্যবহার করা হবে এবং স্ট্রিংয়ের শেষে নাল ক্যারেক্টারের জন্য এক ঘর সংরক্ষিত রাখতে হবে।

কী ধরনের ডেটা টাইপ ব্যবহার করতে হবে সেটি তো ঠিক করলাম, এবার ইনপুট নেওয়ার পালা। scanf("%s", first_line); - এভাবে ইনপুট নিলে হবে না, কারণ প্রথম লাইনে স্পেস ক্যারেক্টারও থাকতে পারে। তাই প্রথম লাইন ইনপুট নিতে হবে এভাবে:

scanf(" %[^\n]", first_line);

আর দ্বিতীয় লাইন ইনপুট নেওয়া এভাবে: scanf("%s", second_line);

আমরা যে অক্ষরটি খুঁজব, সেটি আছে second_line[0]-এ। একটি লুপ ব্যবহার করে প্রথম লাইনের সব অক্ষরের সঙ্গে মিলিয়ে দেখতে হবে যে আমরা যেই অক্ষরটি খুঁজছি, সেটি সেই অক্ষর কি না, যদি তা হয়, তাহলে আমরা যেই ভ্যারিয়েবল ব্যবহার করে গণনা করব, তার মান 1 বাড়িয়ে দিতে হবে।

count = 0;
for(i = 0; i < strlen(first_line); i++)
{
    if(second_line[0] == first_line[i])
    {
        count++;
    }
}

এখন হচ্ছে আউটপুট প্রিন্ট করার পালা। printf() ফাংশন ব্যবহার করে আউটপুট দেওয়ার কাজটি করা যাবে:

printf("Occurrence of '%c' in '%s' = %d\n", second_line[0], first_line, count);

লক্ষ করো যে আমি ফাংশনের ভেতরে একটি নিউলাইন প্রিন্ট করেছি। আর তার আগে পরীক্ষা করতে হবে যে অক্ষরটি একেবারেই না থাকে, তাহলে প্রিন্ট করতে হবে এ রকম করে:

printf("'%c' is not present\n", second_line[0]);

এখন তোমরা কোডটি গুছিয়ে লিখে ফেলো। প্রথমে কম্পাইল ও রান করবে। যেই নমুনা ইনপুট দেওয়া আছে, সেগুলো দিয়ে দেখবে যে নমুনা আউটপুটের সঙ্গে মিলে কি না। নিজে কিছু ইনপুট দিয়েও পরীক্ষা করতে পারো। তারপর এই সমস্যার লিঙ্কে গিয়ে সাবমিট করে দেখো।


সমস্যা ১৫ – অক্ষর গণনা

ইনপুট

প্রথম লাইনে একটি পূর্ণসংখ্যা T (1<=T<=100) থাকবে। পরবর্তীতে T সংখ্যক লাইন থাকবে। প্রতিটি লাইনে থাকবে একটি স্ট্রিং S (S এর দৈর্ঘ্য 1000 এর বেশি নয়)। স্ট্রিংয়ের সবগুলো বর্ণই ছোট হাতের অক্ষরে লেখা থাকবে।

আউটপুট

প্রোগ্রামটির আউটপুটে স্ট্রিং S এ কোন বর্ণটি কতবার আছে সেটি বর্ণানুসারে প্রিন্ট করতে হবে। আউটপুটে "=" চিহ্নের আগে ও পরের স্পেসটি লক্ষণীয়।

ইনপুটআউটপুট
3
hello
baby
programming
e = 1
h = 1
l = 2
o = 1

a = 1
b = 2
y = 1

a = 1
b = 2
g = 2
i = 1
m = 2
n = 1
o = 1
p = 1
r = 2
সমাধান দেখুন

সমাধান

আগের সমস্যাটির সঙ্গে এই সমস্যাটির পার্থক্য কোথায়? আগের সমস্যাতে শুধু একটি বিশেষ বর্ণ একটি স্ট্রিংয়ের মধ্যে কতবার রয়েছে তা গণনা করতে বলা হয়েছিল। আমরা count নামে একটি ভ্যারিয়েবল ব্যবহার করে সেই কাজটি করেছি। আর এই সমস্যায় সবগুলো বর্ণই কতবার রয়েছে তা গণনা করতে বলা হয়েছে। তাহলে এক্ষেত্রে আমাদের 26টি ভ্যারিয়েবল ব্যবহার করতে হবে। তা না করে আমরা 26টি পূর্ণসংখ্যার একটি অ্যারে ব্যবহার করতে পারি।

int count[26];

এখন আমাদের কাজ হচ্ছে এই অ্যারেতে কী বর্ণগুলো গণনা করা। একটা বিষয় খেয়াল রেখো আমরা a কতবার আছে তা রাখব count[0]-তে, b কতবার আছে তা রাখব count[1]-এ, এভাবে করে z কতবার আছে তা রাখব count[25]-এ। এর জন্য আমরা ASCII কোডের ধারণা ব্যবহার করব।

for(i = 0; i < strlen(S); i++)
{
    if(S[i] >= 'a' && S[i] <= 'z')
    {
        count[S[i]-'a']++;
    }
}

মাত্র চার লাইনের কোডেই আমরা কাজটি করে ফেলেছি। তোমরা চিন্তা করে দেখো দেখি বিষয়টি বুঝতে পারো কি না। আমরা প্রথম শর্ত দিয়ে পরীক্ষা করে দেখেছি বর্ণটি a থেকে z এর মধ্যে কি না। তারপর সেই বর্ণের মান থেকে a এর মান বিয়োগ করে যে সংখ্যাটি পাওয়া যায়, count অ্যারের সেই ইনডেক্সের মান এক করে বাড়িয়ে দিয়েছি।

আসলে চার্টটি লক্ষ করো:

'a' = 97'h' = 104'o' = 111'v' = 118
'b' = 98'i' = 105'p' = 112'w' = 119
'c' = 99'j' = 106'q' = 113'x' = 120
'd' = 100'k' = 107'r' = 114'y' = 121
'e' = 101'l' = 108's' = 115'z' = 122
'f' = 102'm' = 109't' = 116
'g' = 103'n' = 110'u' = 117

কম্পিউটার মেমরিতে ঠিক এভাবেই সাংখ্যিক মানে বর্ণগুলোকে রাখা হয়। এই সাংখ্যিক মানগুলোর ওপর বীজগাণিতিক যোগবিয়োগ ব্যবহার করা যায়। যেমন:

'a' - 'a' = 0
'b' - 'a' = 1
'c' - 'a' = 2
'd' - 'a' = 3

তবে এই কোডটি চালানোর আগে অবশ্যই count ভ্যারিয়েবলের সবগুলো ইনডেক্সের মান শূন্য করে নিতে হবে। আর প্রিন্ট করার সময় খেয়াল রাখতে হবে যাদের মান শূন্য সেগুলো যেন আমরা প্রিন্ট না করি:

for(i = 0; i < 26; i++)
{
    if(count[i] != 0)
    {
        printf("%c = %d\n", 'a'+i, count[i]);
    }
}

লক্ষ করো, আমরা আউটপুট প্রিন্ট করার সময়ও 'a'+i কে %c দিয়ে প্রিন্ট করেছি। এটা কীভাবে কাজ করছে তা তোমরা এই চার্টটি দেখলে বুঝতে পারবে।

i'a'+i%d%c
097+0 = 9797a
197+1 = 9898b
297+2 = 9999c
397+3 = 100100d
...
2597+25 = 122122z

আশা করি, তোমরা বিষয়টি বুঝতে পেরেছ। তাহলে এখন এই সমস্যাটি সমাধান করে সাবমিট করে ফেলো।

সমস্যা ১৬ – শব্দ বিপর্যয়

ইনপুট

ইনপুটের প্রথম লাইনে থাকবে টেস্ট কেসের সংখ্যা T (T<=100)। এরপরে T সংখ্যক লাইন থাকবে। প্রতিটি লাইনে থাকবে একটি স্ট্রিং S (S এর দৈর্ঘ্য 1000 এর বেশি নয়)।

আউটপুট

প্রোগ্রামটির আউটপুটে S এর প্রত্যেকটি শব্দকে উল্টো করে প্রিন্ট করতে হবে।

ইনপুটআউটপুট
4
This is a test
Hello World
don't underestimate the
power of a girl
sihT si a tset
olleH dlroW
t'nod etamitserednu eht
rewop fo a lrig
সমাধান দেখুন

সমাধান

এটি একটি স্ট্রিং-সংক্রান্ত সমস্যা। সমস্যাটির সমাধান করতে হলে তোমাদের স্ট্রিং সম্পর্কে পরিষ্কার ধারণা থাকতে হবে। তো আমি আশা করছি তোমাদের মৌলিক ধারণাগুলো তোমরা জানো।

সমস্যার সমাধান করতে গিয়ে প্রথমেই আমরা ইনপুট নেওয়ার ব্যবস্থা করে ফেলি। তোমরা কেউ কেউ gets(S) ফাংশন ব্যবহার করে এক লাইনের স্ট্রিং ইনপুট নাও, কিন্তু এটি ব্যবহার করতে গেলে কিছু সমস্যার পরবে। ব্যবহার করার চেষ্টা করলেই বুঝতে পারবে। এর চেয়ে ভালো হয় scanf(" %[^\n]", S) ব্যবহার করলে। লক্ষ করো, % চিহ্নের আগে কিন্তু একটি স্পেস আছে। সেটি দেওয়ার কারণ হচ্ছে, পূর্বের লাইনের শেষে যেই নিউলাইন ক্যারেক্টার (মানে '\n') আছে, সেটি যেন এর ভেতরে ঢুকে যায়। অর্থাৎ স্পেসের মানে হচ্ছে হোয়াইটস্পেস, তাই নিউলাইন ক্যারেক্টারও এর ভেতরে ঢুকে যাবে। তাহলে নিচের কোড লিখে ফেলতে পারি:

#include<stdio.h>

int main()
{
    int i, T;
    char S[1002], word[1002];

    scanf("%d", &T);
    for (i = 0; i < T; i++)
    {
        scanf(" %[^\n]", S);
        printf("%s\n", S);
    }
    return 0;
}

এখনো আমরা আবার প্রিন্ট করে দেখছি যে ইনপুট যা নিচ্ছি, তা ঠিকঠাক নিচ্ছি কি না। যদি ঠিকঠাক থাকে, তাহলে তোমরা প্রিন্ট করার লাইনটি মুছে দেবে।

এরপরের কাজ হচ্ছে একটি লাইনে যে একাধিক শব্দ আছে, সেগুলো পৃথক করা। সেটা আমরা একটি লুপের মাধ্যমে করে ফেলতে পারি। সমস্যার বর্ণনায় বলা আছে যে শব্দগুলো এক বা একাধিক স্পেস ক্যারেক্টার দিয়ে পৃথক করা আছে। তাহলে আমাদের লজিক কী হতে পারে? S স্ট্রিংয়ের প্রতিটি বর্ণ একটি একটি করে পরীক্ষা করব (শুরু থেকে শেষ পর্যন্ত)। যদি সেটি স্পেস না হয় তাহলে ওই বর্ণটি word অ্যারেতে রাখব। আর যখন S স্ট্রিংয়ের অন্তর্ভুক্ত কোনো স্পেস ক্যারেক্টার পেয়ে যাব, তার মানে আমরা একটি শব্দ পেয়ে গিয়েছি এবং আপাতত সেই শব্দটি প্রিন্ট করব।

#include<stdio.h>
#include<string.h>

int main()
{
    int i, j, k, T, s_len;
    char S[1002], word[1002];

    scanf("%d", &T);
    for (i = 0; i < T; i++)
    {
        scanf(" %[^\n]", S);
        s_len = strlen(S);
        for (j = 0, k = 0; j < s_len; j++)
        {
            if (S[j] != ' ')
            {
                word[k] = S[j];
                k++;
            }
            else if (k > 0)
            {
                word[k] = '\0';
                printf("%s ", word);
                k = 0;
            }
        }
        if (k > 0)
        {
            word[k] = '\0';
            printf("%s\n", word);
        }
    }
    return 0;
}

প্রোগ্রাম রান করে দেখো সব ঠিকঠাক আছে কি না। এখন আমরা প্রতিটি শব্দ আলাদাভাবে প্রিন্ট করতে পারছি। কিন্তু আমাদের শব্দগুলো উল্টো প্রিন্ট করতে হবে। তাই ওই উল্টো প্রিন্ট করার জন্য একটি ফাংশন লিখে ফেলি।

void print_reverse(char str[])
{
    int i;
    for (i = strlen(str) - 1; i >= 0; i--)
    {
        printf("%c", str[i]);
    }
}

এখন কোডে printf("%s\n", word); এর জায়গায় print_reverse(word); লিখতে হবে। তারপরে তুমি যদি তোমার কোডটি রান করো, আউটপুট হিজিবিজি মনে হবে। এর কারণ হচ্ছে শব্দগুলোর মধ্যে স্পেস দাও নি। তাই এরপর দুটি শব্দের মধ্যে স্পেস (একটি স্পেস ক্যারেক্টার) প্রিন্ট করার কাজটি তোমার ওপরই ছেড়ে দিলাম। তবে সবার শেষে যেই শব্দ, তার পরে কিন্তু কিছু স্পেস ক্যারেক্টার দেওয়া চলবে না, দিলে রং আনসার হবে।

সমস্যা ১৭ – স্বরবর্ণ গণনা

ইনপুট

ইনপুটের প্রথম লাইনে থাকবে টেস্ট কেসের সংখ্যা T (T<=100)। এরপরে T সংখ্যক লাইন থাকবে। প্রতিটি লাইনে থাকবে একটি স্ট্রিং S (S এর দৈর্ঘ্য 1000 এর বেশি নয়)। স্ট্রিংয়ের সবগুলো বর্ণই ছোট হাতের অক্ষরে লেখা থাকবে।

আউটপুট

প্রোগ্রামটির আউটপুটে স্ট্রিং S-এর মধ্যে স্বরবর্ণের সংখ্যা (Number of vowels) প্রিন্ট করতে হবে। = চিহ্নের আগের এবং পরের স্পেস লক্ষণীয়।

ইনপুটআউটপুট
3
i am a programmer
happy coding
hello world
Number of vowels = 6
Number of vowels = 3
Number of vowels = 3
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় বলা আছে যে একটি বাক্যে কতগুলো স্বরবর্ণ (vowel) আছে, সেটি বের করতে হবে। সমস্যার বর্ণনায় যদিও বলা নেই, কিন্তু ধরে নিতে পারি যে একটি বাক্য এক লাইনে থাকবে, যদিও এটি বাক্যের সঠিক সংজ্ঞা নয়। প্রোগ্রামিং প্রতিযোগিতায় কোনো সমস্যায় বর্ণনায় এ রকম কনফিউশন থাকলে জাজের কাছে প্রশ্ন পাঠানো যায়। আর স্বরবর্ণ কোনগুলো সেটি মনে না থাকলে আমি বলে দিই - a, e, i, o, u-এই পাঁচটি হচ্ছে ইংরেজি স্বরবর্ণ।

টেস্ট কেসের সংখ্যা ও স্ট্রিংটি ইনপুট নেওয়ার সময় scanf() ফাংশন ব্যবহার করা যেতে পারে। “শব্দ বিপর্যয়” সমস্যার আলোচনায় ইনপুট নেওয়ার পদ্ধতি দেওয়া আছে।

এখন বাকি কাজটি আমি নিজে করি। সমস্যার সমাধান জমা দেওয়ার পর আনসার পেলে আউটপুট ফরম্যাট ঠিক আছে কি না, সেটি পরীক্ষা করতে হবে, আর জাজের সাইজও ঠিক আছে কি না, সেটা দেখতে হবে।


সমস্যা ১৮ – স্বরবর্ণ-ব্যঞ্জনবর্ণ

ইনপুট

ইনপুটের প্রথম লাইনে থাকবে টেস্ট কেসের সংখ্যা T (1<=T<=100)। এরপরে T সংখ্যক লাইন থাকবে। প্রতিটি লাইনে থাকবে একটি স্ট্রিং S। স্ট্রিংয়ের সবগুলো বর্ণই ছোট হাতের অক্ষরে লেখা থাকবে।

আউটপুট

প্রোগ্রামটির আউটপুটে স্ট্রিংটিতে ব্যবহৃত স্বরবর্ণ ও ব্যঞ্জনবর্ণ গুলোকে আলাদা আলাদাভাবে পরপর প্রিন্ট করতে হবে।

ইনপুটআউটপুট
2
this is very easy
it is a rainy sunday
iieea
thssvrysy
iiaaisa
tsrnysndy
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় বলা আছে একটি বাক্যে কতগুলো স্বরবর্ণ এবং ব্যঞ্জনবর্ণ আছে সেগুলো বের করতে হবে। এখানে শুধু vowel আর consonants গুলো আলাদাভাবে প্রিন্ট করতে হবে। তোমরা এর আগে “স্বরবর্ণ গণনা” যে সমস্যাটির সমাধান দেখেছ, সেখানে স্বরবর্ণ বা vowel সম্পর্কে বলা আছে।

আবার আমরা ইনপুটের বর্ণনায় আসি। ইনপুটের বর্ণনায় বলা আছে প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T, পরবর্তী T সংখ্যক লাইনে থাকবে একটি স্ট্রিং। যেহেতু এখানে স্ট্রিং-এর সাইজের ব্যাপারে কোনো উল্লেখ করা হয়নি, আমরা সাইজ 10000 ধরে নিয়ে কাজ করব।

আউটপুটের বর্ণনায় বলা আছে স্বরবর্ণ এবং ব্যঞ্জনবর্ণ আলাদা লাইনে পরপর প্রিন্ট করতে হবে। আমরা এখন আমাদের কোডের জন্য প্রয়োজনীয় ভ্যারিয়েবল ডিক্লেয়ার করে দেই।

char S[10001];
int i, T;

এখানে, S[10001]-আমরা যে বাক্যটি ইনপুট স্ট্রিং হিসেবে নিব সেটির জন্য। i-আমরা যে for লুপটি ব্যবহার করব সেটির জন্য এবং T-T সংখ্যক লাইনে আমরা যে বাক্যটি নিতে চাচ্ছি তার জন্য।

প্রথমে আমাদের ইনপুট নেওয়ার কাজটি করে ফেলি। অনেক সময় তোমরা gets() ব্যবহার করে ইনপুট নিয়ে থাকো। কিন্তু, gets() দিয়ে স্ট্রিং ইনপুট নেওয়ার সময় একটি সমস্যা হয়। যেটা স্ট্রিং ইনপুট নেওয়ার সময়ই বুঝতে পারবে।

যেহেতু, T সংখ্যক লাইন ইনপুট নিতে হবে তাই আমাদের প্রথম ইনপুট হবে T।

scanf("%d", &T);

লুপটি T-এর মান যত ততবার চলবে।

for(i = 0; i < T; i++) { }

লুপটি যতবার চলবে, প্রতিবার আমরা S স্ট্রিংটি ইনপুট নিব। scanf(" %[^\n]", S) ব্যবহার করলে। লক্ষ করো, % চিহ্নের আগে একটি স্পেস আছে। সেটি দেওয়ার কারণ হচ্ছে, আগের লাইনের শেষে যে নিউলাইন ক্যারেক্টার (মানে '\n') আছে, সেটি যেন এর ভেতরে ঢুকে যায়। এখানে স্পেসের মানে হচ্ছে হোয়াইটস্পেস, তাই নিউলাইন ক্যারেক্টারও এর ভেতরে ঢুকে যাবে।

ইনপুট নেওয়ার পর আরেকটি for ব্যবহার করে S-এ নাল ক্যারেক্টার ('\0') না পাওয়া পর্যন্ত এগিয়ে যাবে। আমাদের লুপটি হবে এমন:

for(i = 0; S[i] != '\0'; i++) { }

লুপের ভেতরে আমরা একটি কন্ডিশন দিয়ে বিচার করে vowel-গুলো আলাদা করে ফেলব এবং আউটপুট হিসেবে সেগুলো প্রিন্ট করব।

for(i = 0; S[i] != '\0'; i++)
{
    if(S[i] == 'a' || S[i] == 'e' || S[i] == 'i' || S[i] == 'o' || S[i] == 'u')
    {
        printf("%c", S[i]);
    }
}

এবার খেয়াল করে দেখো, উদাহরণ আউটপুটের দিকে। সেখানে consonants প্রিন্ট করার আগে একটি নিউলাইন প্রিন্ট করা আছে। কিন্তু সমস্যার বর্ণনায় সেটি বলা নেই। কিন্তু এটি দিতে হবে। তাই ওই for লুপটির পরে একটি নিউলাইন প্রিন্ট করব।

printf("\n");

এবার আবার consonants বা ব্যঞ্জনবর্ণের জন্য আবার একটি লুপের সাহায্য নিয়েছি। যেটি প্রায় আগের for লুপটির মতোই শুধুমাত্র "==" এর পরিবর্তে সেখানে আমরা "!=" ব্যবহার করেছি। এখন তোমাদের মনে আসতে পারে, if এর পরে else ব্যবহার করলেই তো আমরা consonants বা ব্যঞ্জনবর্ণগুলো পেয়ে যেতাম। এই প্রশ্নের উত্তর তোমরা if এর পরে else ব্যবহার করলেই পেয়ে যাবে। আমাদের কোডটি হবে এমন:

for(i = 0; S[i] != '\0'; i++)
{
    if(S[i] != 'a' && S[i] != 'e' && S[i] != 'i' && S[i] != 'o' && S[i] != 'u' && S[i] != ' ')
    {
        printf("%c", S[i]);
    }
}

খেয়াল করে দেখ শব্দগুলোর শেষে আবার কিন্তু আমি আরও একটি শর্ত জুড়ে দিয়েছি। এবার তোমাদের কাজ হলো কোডটি গুছিয়ে সুন্দর করে লিখে ফেলা।

সমস্যা ১৯ – শব্দ গণনা ১

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে ইনপুট হবে একটি করে স্ট্রিং S, S-এর সর্বোচ্চ দৈর্ঘ্য হবে 10000। প্রতিটি স্ট্রিংয়ে দুটি শব্দ একটিমাত্র স্পেস (' ') ক্যারেক্টার দিয়ে আলাদা করা থাকবে। স্ট্রিংটিতে ইংরেজি বর্ণ ও স্পেস ছাড়া অন্য কোনো ক্যারেক্টার থাকবে না।

আউটপুট

প্রোগ্রামটির আউটপুটে S-এ মোট কতগুলো শব্দ আছে সেটি গণনা করে দেখাতে হবে। আউটপুটে "=" চিহ্নের আগে এবং পরে একটি করে স্পেস দিতে হবে।

ইনপুটআউটপুট
3
Hello World
Dhaka is the capital of Bangladesh
It is the winter of discontent
Count = 2
Count = 6
Count = 6
সমাধান দেখুন

সমাধান

এক লাইনের একটি স্ট্রিংয়ের স্পেসগুলোর থেকে আমরা ওই স্ট্রিংয়ে কতগুলো শব্দ আছে সেটি বের করতে পারি। এখানে আমাদের যদি একটি substring এ আলাদা আলাদা করে একটি ভ্যারিয়েবলে হিসাব করি তাহলেই মোট কত শব্দ আছে সেটি পেয়ে যাব।

আমাদের বিবেচনায় আনতে হবে স্পেস কয়টি সেটি গণনা করা। ধরা যাক, একটি স্ট্রিং আমরা ইনপুট নিয়েছি “Hello World”। এখানে দুটি শব্দের মধ্যে স্পেস আছে একটি। তাহলে আমাদের শব্দের সংখ্যা হবে এক বেশি।

আমরা শুধু গণনা করব স্ট্রিং S নাল ক্যারেক্টার না পাওয়া পর্যন্ত চলবে এবং স্পেসের সংখ্যা গণনা করে প্রিন্ট করব। কোডের এই অংশটুকু হবে এমন:

int count = 0;
for(i = 0; S[i] != '\0'; i++)
{
    if(S[i] == ' ')
    {
        count++;
    }
}
printf("%d", count+1);

তবে খেয়াল করো, যদি দুটি শব্দের মধ্যে একাধিক স্পেস ক্যারেক্টার থাকে তখন কিন্তু এই প্রোগ্রাম কাজ করবে না। কোডের বাকি অংশটুকু লেখা তোমাদের কাজ। পুরো কোডটি লিখে নমুনা ইনপুট/আউটপুটের সঙ্গে মিলিয়ে দেখো সব ঠিকঠাক দেখায় কি না। তারপর অনলাইন জাজে জমা দাও।

সমস্যা ২০ – শব্দ গণনা ২

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে প্রোগ্রামটির ইনপুট হবে একটি করে স্ট্রিং S। স্ট্রিং এর সর্বোচ্চ সীমা 10000।

আউটপুট

প্রোগ্রামটির আউটপুটে মোট কতগুলো শব্দ S-এ আছে সেটি count করে দেখাতে হবে। আউটপুটে "=" চিহ্নের আগে এবং পরে একটি করে স্পেস দিতে হবে।

ইনপুটআউটপুট
2
Hurrah! was heard on all sides.
Hello, I'm Brooker and you're watching TV.
Count = 6
Count = 7
সমাধান দেখুন

সমাধান

শব্দ গণনা-১ সমস্যাটির মতোই এই সমস্যাটি। এখানে স্পেস ছাড়াও আমাদের আরও অন্যান্য যদি চিহ্ন দিয়ে কাজ করতে হয়। অর্থাৎ যদি কোনো বাক্যে কমা (,) বা সেমিকোলন (;) ইত্যাদি থাকে তাহলে সেগুলো বিবেচনা করে আমাদের প্রতিটি শব্দ আলাদা করতে হবে। এখানে আমরা প্রতিটি শব্দ আলাদা করার জন্য strtok() ফাংশনের সাহায্য নিতে পারি।

strtok() ফাংশন দিয়ে একটি স্ট্রিং-কে ছোট ছোট ভাগে ভাগ করা যায়, যাকে string tokenization বলা হয়ে থাকে। strtok()-এর দুটি প্যারামিটার হবে যে স্ট্রিং-টি আমরা ইনপুট হিসেবে নেব এবং দ্বিতীয় প্যারামিটার হলো যেসব চিহ্ন দিয়ে আমরা শব্দগুলোকে আলাদা করব। প্রথম শব্দটি আমরা এভাবে পেয়ে যাব এবং সেই একটি ক্যারেক্টার পয়েন্টারে ভ্যারিয়েবলে রাখব। স্ট্রিংয়ের বাকি শব্দগুলো পাওয়ার জন্য আমরা একটি লুপ চালাব NULL পর্যন্ত।

strtok() দিয়ে কোডটি হবে এমন:

word = strtok(S," ,!;?.\n");
count = 0;
while(word != NULL)
{
    if(strlen(word) > 0)
    {
        count++;
    }
    word = strtok(NULL, " ,!;?.\n");
}
printf("%d\n",count);

এখানে word হচ্ছে char *word। কোডটির প্রথম লাইনে আমরা স্ট্রিংটির প্রথম শব্দটি আলাদা করেছি। এরপর আরও একটি ক্যারেক্টার পয়েন্টার token-এর সাহায্যে আমরা স্ট্রিংটি NULL পয়েন্টার না পাওয়া পর্যন্ত পরীক্ষা করেছি। word-এর length শূন্য না হওয়া পর্যন্ত count করেছি মোট কতগুলো শব্দ আমরা পাচ্ছি।

বাকি কাজ এখন তোমাদের।


সমস্যা ২১ – উল্টে দেখা

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে প্রোগ্রামটির ইনপুট হবে একটি করে স্ট্রিং S। স্ট্রিং এর সর্বোচ্চ দৈর্ঘ্য হবে 1000।

আউটপুট

প্রোগ্রামটির আউটপুটে, S স্ট্রিংটিকে উল্টো করে প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
string
programming
Aruna
gnirts
gnimmargorp
anurA
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় বলা আছে ইনপুট হবে পূর্ণ সংখ্যা T এবং একটি স্ট্রিং S; যেখানে স্ট্রিং S এর সর্বোচ্চ দৈর্ঘ্য হবে 1000। এখন ইনপুট T এর জন্য আমরা ডেটা টাইপ হিসেবে নিব int এবং স্ট্রিং ইনপুটের জন্য নিব একটি ক্যারেক্টার অ্যারে।

int T;
char S[1001];

কী ধরনের ডেটা টাইপ ব্যবহার করে ইনপুট নিতে হবে সেটি তো আমরা ঠিক করলাম। এখন ইনপুট নেওয়ার পালা। যেহেতু বলা আছে T সংখ্যক লাইনে ইনপুট নিতে হবে, সেক্ষেত্রে আমরা প্রথমে ইনপুট নিব T।

scanf("%d", &T);

T সংখ্যক লাইনে ইনপুট নেওয়ার জন্য আমাদের একটি লুপ ব্যবহার করতে হবে যেটি T সংখ্যকবার চলবে। এক্ষেত্রে while বা for লুপ ব্যবহার করতে পারি।

while(T--) { } অথবা for(int i = 0; i < T; i++) { }

এবার স্ট্রিং ইনপুট নেওয়ার ব্যাপারে অনেকগুলো সমস্যা বলা আছে। মনে না থাকলে আগের ব্যাপারে বিস্তারিত বললাম না।

এখানে সমস্যাটির সমাধানের জন্য লুপ ব্যবহার করেছি। এজন্য, প্রথমেই আমাদের দরকার ইনপুট স্ট্রিং-টির দৈর্ঘ্য। এখানে আমরা strlen() ফাংশন ব্যবহার করেছি। স্ট্রিং এর দৈর্ঘ্য থেকে শুরু করে এক এক করে কমিয়ে আমরা লুপটিতে শূন্যতে এসে থেমেছি এবং প্রিন্ট করেছি।

#include<stdio.h>
#include<string.h>

int main()
{
    char S[1001];
    int i, T, len;

    while(T--)
    {
        scanf(" %[^\n]", S);
        len = strlen(S);
        for(i = len-1; i >= 0; i--)
        {
            printf("%c", S[i]);
        }
        printf("\n");
    }
    return 0;
}

এই কোডটি লিখে রান করলে তোমরা দেখবে কোডটি ঠিকমতো কাজ করে কি না। যদি না করে ভুলগুলো নিজে নিজে ঠিক করে তার জন্য চেষ্টা জমা দেবে।

সমস্যা ২২ – মৌলিক সংখ্যা

ইনপুট

প্রোগ্রামটির ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে প্রোগ্রামটির ইনপুট হবে দুটি পূর্ণসংখ্যা ab (1<=a<=b<=100000)।

আউটপুট

প্রোগ্রামটির আউটপুটে a থেকে b পর্যন্ত কতগুলো মৌলিক সংখ্যা আছে তা প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
1 5
25 50
12 27
3
6
4
সমাধান দেখুন

সমাধান

এই সমস্যার সমাধান করতে গিয়ে সবচেয়ে সহজ পদ্ধতি হচ্ছে, ইনপুটে যে দুটি সংখ্যা থাকবে (a ও b, যেখানে a <= b), একটি লুপ চালিয়ে তার ভেতর থেকে শেষ পর্যন্ত প্রতিটি সংখ্যা মৌলিক কি না পরীক্ষা করা এবং মৌলিক হলে গণনা করা। সবশেষে মোট কয়টি মৌলিক সংখ্যা পাওয়া গেল, সেটি প্রিন্ট করা। তবে এটি মোটেও ভালো কোনো পদ্ধতি নয়। প্রোগ্রামিং প্রতিযোগিতার সময় তোমরা এভাবে সমাধান করলে টাইম লিমিট এক্সিডেড এরর পাবে।

যেহেতু সংখ্যাগুলো 1 থেকে 100000-এর মধ্যে, তাই আমরা শুরুতেই সিভ মেথডের সাহায্যে এই সীমার মধ্যে কোনগুলো মৌলিক সংখ্যা আর কোনগুলো মৌলিক নয়, সেগুলো বের করে ফেলব। তারপরে আমরা ইনপুট নেওয়ার পর আর একটি লুপ চালিয়ে বলে দিতে পারব যে ওই সীমার মধ্যে কয়টি মৌলিক সংখ্যা আছে। তোমরা যদি মৌলিক সংখ্যা বের করার সিভ মেথডের সঙ্গে পরিচিত না হয়ে থাকো, তাহলে “কম্পিউটার প্রোগ্রামিং - ১ম খণ্ড” বইটির মৌলিক সংখ্যা অধ্যায়টি ভালো করে পড়ে নিও।

তাহলে তোমাদের কোড দাঁড়াবে অনেকটা এ রকম:

#include<stdio.h>
#include<math.h> // sqrt ব্যবহারের জন্য
#define size 100001
char ara[size];

void sieve()
{
    int i, j, root;
    for(i = 2; i < size; i++) {
        ara[i] = 1;
    }
    root = sqrt(size);
    for(i = 2; i <= root; i++) {
        if(ara[i] == 1) {
            for(j = 2; i * j <= size; j++) {
                ara[i * j] = 0;
            }
        }
    }
}

int main()
{
    int T, a, b, count;
    sieve();
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d %d", &a, &b);
        count = 0;
        for(i = a; i <= b; i++) {
            if(ara[i]) {
                count++;
            }
        }
        printf("%d\n", count);
    }
    return 0;
}

এখানে দেখো আমি শুরুতেই সিভ মেথড কল করেছি, এবং এই ফাংশনের কাজ হচ্ছে ara-এর ভেতর যেসব সংখ্যা মৌলিক, সেখানে 1 আর যেসব সংখ্যা মৌলিক নয়, সেখানে 0। এই কাজটি আমার করা শেষ। তারপরে ইনপুট নেওয়ার পর আমি সেই অ্যারের ভেতর একটি লুপ চালিয়ে বলে দিতে পারব ওই সীমার মধ্যে কয়টি মৌলিক সংখ্যা আছে। এ রকম মাঝে মধ্যে তোমরা কিছু প্রোগ্রামিং সমস্যা পাবে, যেখানে আগে-ভাগে হিসাব করে রাখতে পারলে পরে দ্রুত উত্তর দেওয়া যায়। আশা করি, এই পদ্ধতিটি তোমার আয়ত্তে এনে ফেলতে পারবে।

সমস্যা ২৩ – বর্ণমালা থেকে সংখ্যা

ইনপুট

প্রোগ্রামটির ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে প্রোগ্রামটির ইনপুট হবে একটি স্ট্রিং S (S এর দৈর্ঘ্য 100 এর বেশি নয়)। স্ট্রিংয়ের সবগুলো বর্ণই বড় হাতের অক্ষরে লেখা থাকবে।

আউটপুট

প্রোগ্রামটির আউটপুটে স্ট্রিং S-এর প্রতিটি অক্ষরের সাংখ্যিক মান প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
ABZ
ZYB
CODING
1226
26252
31549147
সমাধান দেখুন

সমাধান

দেখতে মনে হলেও আসলে এটি খুবই সহজ একটি প্রোগ্রামিং সমস্যা। ASCII কোডের সাহায্যে আমরা এই সমস্যাটির সমাধান করব। এখন প্রশ্ন হচ্ছে ASCII কোড কী? ক্যারেক্টারের সাংখ্যিক রূপ হচ্ছে ASCII কোড। uppercase ক্যারেক্টারের ASCII কোড কিন্তু আলাদা। যেমন: 'A'-এর ASCII কোড 65 এবং 'a'-এর ASCII কোড 97। সমস্যাটি ভালোভাবে করলে দেখবে এখানে শুধুমাত্র uppercase letters অর্থাৎ সাধারণ বাংলায় যেগুলোকে বড় হাতের অক্ষর বলে সেগুলো নিয়ে কাজ করা হয়েছে।

যেহেতু কাজ শুধু uppercase অক্ষরগুলো নিয়ে কাজ করতে হবে। ASCII কোডের মানগুলো ক্রমবর্ধমান, অর্থাৎ 'A'-এর কোড 65, 'B'-এর কোড 66 এভাবে বাড়তে থাকবে। এখন থেকে ইংরেজি 26টি বর্ণের জন্য ASCII কোড বের করতে ফেললে পারবে। তাহলে এই কোডটি করার জন্য আমাদের A-Z পর্যন্ত 26টি বর্ণের ASCII কোড নিয়ে কাজ করতে হবে।

প্রোগ্রামটির আউটপুটের বর্ণনায় বলা আছে প্রতিটি অক্ষরের সাংখ্যিক মান প্রিন্ট করতে হবে। মানে 'A' = 1, 'B' = 2, 'C' = 3,..., 'Z' = 26। এখন নমুনা ইনপুট/আউটপুট খেয়াল করে দেখো: ABZ ইনপুট হলে আউটপুট 1226। 'A'-এর সাংখ্যিক মান 1। যদি 'A'-এর ASCII কোড 65 থেকে আমরা 64 বিয়োগ দেই, তাহলে আমরা 1 পেয়ে যাব। আবার যদি 'B'-এর ASCII কোড 66 থেকে আমরা 64 বিয়োগ দেই, আমরা 'B'-এর সাংখ্যিক মান 2 পাব। অর্থাৎ, প্রতিটি কোড থেকে 64 বিয়োগ দিলে আমরা সাংখ্যিক মান পেয়ে যাব।

আমাদের যেহেতু স্ট্রিং নিয়ে কাজ করতে হবে, তাই প্রথমেই আমাদের স্ট্রিং ইনপুট নিতে হবে। আমরা স্ট্রিংটিতে '0' না পাওয়া পর্যন্ত একটি লুপ চালাব। আমাদের 'A' থেকে 'Z' পর্যন্ত অক্ষরগুলোকে বিবেচনায় আনার জন্য একটি কন্ডিশন ব্যবহার করতে হবে। আমাদের কোডটি হবে এমন:

for(i = 0; S[i] != '\0'; i++)
{
    if(S[i] >= 'A' && S[i] <= 'Z')
    {
        printf("%d", S[i] - 64);
    }
}

ভালোভাবে লক্ষ করো printf() ফাংশনটিতে আমি ইন্টিজারের ফরম্যাট স্পেসিফায়ার %d ব্যবহার করেছি। কিন্তু কেন? কারণ, আমাদের অক্ষরের সাংখ্যিক মান (Numerical Value) দরকার এজন্য আমাদের ক্যারেক্টারটির ASCII কোড জানা জরুরি। প্রিন্ট ফাংশনে আমরা সেই কাজটিই করেছি। অর্থাৎ কোড থেকে 64 বিয়োগ করে দিয়েছি।

এখন তোমরা প্রোগ্রামটি লিখে পরীক্ষা-নিরীক্ষা করো এবং অনলাইন জাজে জমা দাও। আশা করি সমাধান সঠিক হবে।

একটি প্রোগ্রামিং সমস্যা আমরা অনেকভাবেই সমাধান করতে পারি। ওপরে তো তোমরা আসকি কোড নিয়ে কাজ করলে, এখন দেখা যাক অন্য কোনো বুদ্ধি বের করা যায় কি না। নিচের কোডটি লক্ষ করো:

#include<stdio.h>

int main()
{
    char c1, c2, c3;
    c1 = 'A';
    c2 = 'B';
    c3 = 'C';

    printf("%d, %d, %d\n", c1 - 'A', c2 - 'A', c3 - 'A');

    return 0;
}

প্রোগ্রামটি রান করে কয়েক মিনিট চিন্তা করলেই তোমরা বুঝে ফেলবে কত সহজে আমরা সমস্যাটির সমাধান করে ফেলতে পারি, আর পুরো কোডটিতে তেমন বেগ পেতে হবে না। আর কোডটি সঠিক হল কি না, সেটি অনলাইন জাজে দিলেই বুঝতে পারবে।


সমস্যা ২৪ – একান্তর উপাদান

ইনপুট

প্রোগ্রামটির ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে প্রোগ্রামটির ইনপুট হবে একটি পূর্ণসংখ্যা n (1<=n<=100), যা অ্যারের উপাদান সংখ্যা নির্দেশ করে। পরবর্তীতে অ্যারের n সংখ্যক উপাদান ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে অ্যারের একান্তর উপাদানগুলো পাশাপাশি প্রিন্ট করতে হবে। প্রতিটি উপাদান একটি স্পেস ক্যারেক্টার দিয়ে আলাদা থাকবে।

ইনপুটআউটপুট
2
5 1 2 3 4 5
10 1 4 55 66 22 0 76 11 23 78
1 3 5
1 55 22 76 23
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় বলা আছে একটি অ্যারের উপাদানগুলো (elements) থেকে একান্তর উপাদানগুলো প্রিন্ট করতে হবে। যদি অ্যারেতে দেওয়া থাকে পাঁচটি উপাদান আছে যথাক্রমে: 1 2 3 4 5। পাঁচটি উপাদান এই অ্যারেটির একান্তর হবে 1 3 5। বিজোড় সংখ্যাগুলো কিন্তু নয়, এখানে প্রথম ইনডেক্স থেকে শুরু করে প্রতিবার এক ঘর করে উপাদান বাদ দেওয়া হয়েছে। অর্থাৎ, 1 আছে কিন্তু 2 নেই, 3 আছে কিন্তু 4 নেই আবার 5 আছে।

এখানে ইনপুটের বর্ণনা অনুসারে সমস্যার মতোই। T সংখ্যক লাইনে ইনপুট নিতে হবে। প্রথমে ইনপুট হবে n, মানে কতগুলো সংখ্যা অ্যারেতে থাকবে। এরপর ইনপুট হবে n সংখ্যক অ্যারের উপাদান।

scanf("%d", &n);
for(i = 0; i < n; i++)
{
    // অ্যারে ইনপুট নিতে হবে এখানে
}

অ্যারের উপাদান প্রিন্ট করার সময় তোমরা প্রিন্ট করতে পারো। অ্যারের উপাদান প্রিন্ট করার সময় আমরা for লুপটিকে এক এক করে বৃদ্ধি (increment) করি। যেটি অ্যারের ইনডেক্সের মান। একটি উপাদান বাদ দেওয়ার সময় যদি লুপটিকে 2 করে increment করি তাহলেই আমাদের কাজ হয়ে যাবে।

একটি উদাহরণ দিয়ে ব্যাপারটি পরিষ্কার হবে।

int num[5] = {1, 2, 3, 4, 5};

এখানে,

num[0] = 1;
num[1] = 2;
num[2] = 3;
num[3] = 4;
num[4] = 5;

প্রথম অ্যারের উপাদানটি অর্থাৎ ইনডেক্স 0 এর উপাদান 1, ইনডেক্সের মান যদি আমরা 2 বাড়াই তাহলে ইনডেক্সের বর্তমান মান হবে i = 0+2=2, আমাদের num[2] = 3। আবার আমরা ইনডেক্সের মান দুই বৃদ্ধি করি তাহলে ইনডেক্সের মান হবে, 4। তখন আমরা প্রিন্ট করব num[4] = 5। এভাবে আমরা আউটপুটে একান্তর অ্যারের উপাদানগুলো পেয়ে যাব।

for(i = 0; i < n; i+=2)
{
    // এখানে আউটপুট প্রিন্ট করতে হবে
}

বাকিটা এখন তোমাদের।

সমস্যা ২৫ – লঘিষ্ঠ সাধারণ গুণিতক

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেস নির্দেশ করে। প্রতি T সংখ্যক টেস্ট কেসের জন্য প্রোগ্রামটির ইনপুট হবে দুটি পূর্ণসংখ্যা a এবং b (1<=a, b<=100000)।

আউটপুট

প্রোগ্রামটির আউটপুটে a এবং b এর লঘিষ্ঠ সাধারণ গুণিতক বা LCM প্রিন্ট করতে হবে। আউটপুটে "=" চিহ্নের আগের এবং পরের স্পেস ক্যারেক্টার লক্ষণীয়।

ইনপুটআউটপুট
2
30 15
12 16
LCM = 30
LCM = 48
3
14 35
4 6
105 15
LCM = 70
LCM = 12
LCM = 105
সমাধান দেখুন

সমাধান

ল.সা.গু বা লঘিষ্ঠ সাধারণ গুণিতকের সঙ্গে তোমরা পরিচিত। স্কুল কলেজে তোমরা এই সম্পর্কিত অনেক সমস্যার সমাধান করেছ। ল.সা.গু বের করার একটি সহজ সূত্র আছে।

দুটি সংখ্যার ল.সা.গু × দুটি সংখ্যার গ.সা.গু = দুটি সংখ্যার গুণফল।

তোমরা দুটি সংখ্যার গসাগু অবশ্যই বের করতে পারো। এখন দুটি সংখ্যার গ.সা.গু যদি বের করা যায় তাহলে এই সূত্রের সাহায্যে আমরা ল.সা.গু বের করতে পারব। ইউক্লিডীয় অ্যালগরিদমের সাহায্যে গ.সা.গু বের করার একটি চমৎকার পদ্ধতি আছে। অ্যালগরিদমটি এমন:

function gcd(a, b)
    while b ≠ 0
       t := b; 
       b := a mod b; 
       a := t; 
    return a;

একটি উদাহরণ দিলে ফাংশনটির কার্যক্রম আমাদের কাছে পরিষ্কার হবে। ধরা যাক, a=12 এবং b=16, এদের গ.সা.গু বের করতে হবে। অ্যালগরিদম অনুযায়ী:

  1. a=12, b=16
  2. while(b!=0) এভাবে b এর মান যতক্ষণ 0 না হবে লুপটি ততবার চলবে। অর্থাৎ লুপের ভেতরে তিনটি ধাপ আমরা b এর মান 0 না হওয়া পর্যন্ত বারবার করতে থাকব।
  3. t=16; b=12%16 এখানে যেহেতু 12 কে 16 দিয়ে ভাগ করা যায় না, তাই ভাগশেষ হবে 12, সুতরাং b=12, a=t=16 (যেহেতু, প্রথমেই আমরা t এর মান 16 দিয়েছি)।
  4. দ্বিতীয় ধাপে এসে আমরা a এর নতুন মান পেয়েছি, a = 16 এবং b = 12। এখন আমাদের t=12; b=a%b=16%12=4; a=t=12
  5. এখন a=12, b=4 এবং t=b=4; b=a%b=12%4=0; a=4; এখানে আমরা b এর মান শূন্য পেয়ে গেলাম তাই এই লুপটি এখানেই শেষ হয়ে যাবে। এটি a এর মান return করবে 4।

নিচে চার্ট আকারে এই ইউক্লিডীয়ান দেখানো হলো:

b!=0tba
truet ← b = 16b ← a % b
← 12 % 16
← 12
a ← t = 16
truet ← b = 12b ← a % b
← 16 % 12
← 4
a ← t = 12
truet ← b = 4b ← a % b
← 12 % 4
← 0
a ← t = 4
falsestopstopstop

gcd() ফাংশনের কোডটি হবে এমন:

int gcd(int a, int b)
{
    int temp;
    while(b != 0)
    {
        temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

আমি এখানে gcd() পর্যন্ত কোড লিখে দিলাম। এটি দিয়ে তোমরা দুটি সংখ্যার গ.সা.গু বের করতে পারবে। এরপর ল.সা.গু বের করার যে সূত্রটি ওপরে উল্লেখ করেছি সেটির সাহায্যে ল.সা.গু বের করার প্রোগ্রামটি আউটপুট লিখে অনলাইন জাজে জমা দাও।

সমস্যা ২৬ – এলিয়েন গুপি

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=1000) যেটি টেস্ট কেসের সংখ্যা দেখায়। প্রতিটি টেস্ট কেসে একটি বাস্তব সংখ্যা X ইনপুট নিতে হবে যেটি মোট খাবারের পরিমাণ নির্দেশ করে (0.0 <= X <= 100000.0)।

আউটপুট

প্রোগ্রামটির আউটপুটে X কেজি খাবার শেষ করতে গুপির কতদিন সময় লাগবে সেটি প্রিন্ট করতে হবে "days" হিসেবে।

ইনপুটআউটপুট
3
40.0
200.0
300.0
6 days
8 days
9 days
সমাধান দেখুন

সমাধান

খুব সহজ একটি সমস্যা। সমস্যার বর্ণনায় বলা আছে, ফিরিফিরি গ্রহের প্রাণীরা প্রতিদিন সরবরাহকৃত খাবারের অর্ধেক খায় একদিনে। সরবরাহকৃত খাবার শেষ হতে কতদিন লাগবে গুপির আমাদের সেটি বের করতে হবে। অর্থাৎ তার গ্রহ থেকে কতদিনের খাবার নিয়ে আসতে মোট বের করতে হবে।

প্রোগ্রামটির বর্ণনায় বলা আছে T সংখ্যক লাইন ইনপুট নেওয়ার কথা। আমাদের ইনপুট হবে দুটি সংখ্যা- একটি টেস্ট কেসের সংখ্যা T এবং অন্যটি দশমিক সংখ্যা যা খাবারের পরিমাণ নির্দেশ করে।

scanf("%d", &T);
for(i = 0; i < T; i++)
{
    scanf("%lf", &X);
}

এখানে X হচ্ছে গুপির সঙ্গে আনা খাবারের পরিমাণ। গুপী যেহেতু X-এর অর্ধেক খাবার খায়, তাহলে কতদিন X পরিমাণ খাবার খেতে পারবে সেটি হিসাব করার জন্য আমরা আরেকটি ভ্যারিয়েবল count ব্যবহার করব। আউটপুটে হবে count-এর মোট মান।

বর্ণনায় বলা আছে ১ কেজির কম যখন খাবারের পরিমাণ হয়ে যাবে গুপী তখন তার গ্রহে ফিরে যাবে। তাহলে আমরা একটি লুপ চালাব যেটি কিনা X-এর মান 1.0 থেকে ছোট না হওয়া পর্যন্ত চলবে। X-এর ডেটা টাইপ যেহেতু double তাই আমরা 1.0 লিখেছি।

while(X > 1.0)
{
    X = X / 2;
    count++;
}
printf("%d\n", count);

আমাদের সম্পূর্ণ কোডটি হবে এমন:

#include<stdio.h>

int main()
{
    int T, count;
    double X;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%lf", &X);
        count=0;
        while(X > 1.00)
        {
            X = X / 2;
            count++;
        }
        printf("%d days\n", count);
    }
    return 0;
}

কোডটি তোমরা লিখে রান করে নমুনা ইনপুট/আউটপুট দিয়ে ভালোভাবে দেখে নাও। যদি কোনো সমস্যা বা অমিল দেখতে পাও নিজেরা চেষ্টা করে ঠিক করো।


সমস্যা ২৭ – আর্মস্ট্রং সংখ্যা

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে ইনপুট হবে একটি তিন অঙ্কের পূর্ণসংখ্যা n (100 <= n <= 999)

আউটপুট

প্রোগ্রামটির আউটপুটে যদি n আর্মস্ট্রং সংখ্যা হয় তাহলে প্রিন্ট করতে হবে "n is an armstrong number!" অন্যথায় প্রিন্ট করতে হবে "n is not an armstrong number!"।

ইনপুটআউটপুট
3
100
153
371
100 is not an armstrong number!
153 is an armstrong number!
371 is an armstrong number!
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় বলা আছে, একটি সংখ্যার প্রতিটি অঙ্ককে তাদের মোট অঙ্কের সমান পাওয়ার বা শক্তি দিয়ে বৃদ্ধি করার পর, অঙ্কগুলোকে আলাদাভাবে যোগ করে যোগফল যদি আবার সেই সংখ্যাটি পাওয়া যায় তবে সেই সংখ্যাটিকে আর্মস্ট্রং সংখ্যা বলে। সমস্যার উদাহরণ দিয়ে ব্যাপারটি বোঝানো হয়েছে।

সমস্যাটির ইনপুটের বর্ণনার সঙ্গে তোমরা পরিচিত। T সংখ্যক লাইনে ইনপুট নিতে হবে একটি পূর্ণসংখ্যা n। সমস্যার n-এর রেঞ্জ উল্লেখ করা আছে। যেহেতু বলা হয়েছে তিন অঙ্কের সংখ্যা তাই আমাদের চিন্তার কিছু নেই। এখানে সবসময়ই আমাদের সংখ্যার অঙ্কগুলোর পাওয়ার হবে 3।

এখন তিন অঙ্কের একটি সংখ্যাকে আমরা যদি 10 দিয়ে ভাগ করি তাহলে ভাগশেষ থেকে তবে সেটি এককের ঘরের অঙ্কটি এবং ভাগফল হবে দশক এবং শতকের ঘরের অঙ্কটি।

ধরা যাক,

আমাদের সংখ্যাটি, n = 153
ভাগশেষ, rem = 153%10 = 3
n = 153/10 = 15

এখন আমাদের ভাগশেষ 3-কে যদি আমরা তিনবার গুণ করি তাহলে আমরা 3³ পেয়ে যাব। এখানে ভাগ করার পর আমাদের ভাগফল হচ্ছে 15 যেটি আমাদের n-এর নতুন মান হবে। যদি আমরা আবার n-কে 10 দ্বারা ভাগ করি, তখন আমরা ভাগফল পাব 1 এবং ভাগশেষ পাব 5। এই ভাগশেষ 5-কে যদি আমরা তিনবার গুণ করি তাহলে পাব 5³। এখন n-এর বর্তমান মান 1। 1-কে 10 দিয়ে ভাগ করলে ভাগফল হিসেবে পাব শূন্য, কারণ 1<10 দিয়ে দেওয়া যায় না। ভাগশেষ পাব 1। 1-কে যদি আমরা তিনবার গুণ করি তাহলে পাব 1³।

এখন আমরা যদি 3³, 5³, 1³ যোগ করি তাহলে আমরা আমাদের ইনপুট সংখ্যা n পেয়ে যাব। এখানে তোমরা লক্ষ করে দেখেছো, আমরা দুটি কাজ বারবার করেছি। ভাগশেষ এবং ভাগফল বের করা যতক্ষণ না n-এর মান শূন্য হয়। আমাদের একটি লুপ ব্যবহার করতে হবে। প্রতিটি অঙ্ককে ঘনফলকে যোগ করতে হবে। যদি যোগ করার পর প্রাপ্ত সংখ্যাটি n-এর সমান হয় তাহলে আমরা বলতে পারব n একটি আর্মস্ট্রং সংখ্যা।

আমাদের কোডটি হবে এমন:

#include<stdio.h>

int main()
{
    int n, T, res = 0, rem, temp = 0;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        temp = n;
        res = 0;
        while(temp != 0)
        {
            rem = temp % 10;
            res += rem * rem * rem;
            temp /= 10;
        }
        // এখানে আউটপুট প্রিন্ট করার জন্য কোনো কিছু লিখি নি। সেটি তোমাদের কাজ।
        // একটু চিন্তা করে কন্ডিশনাল আউটপুট তোমরা লিখে ফেলো।
    }
    return 0;
}

সমস্যা ২৮ – এলোমেলো অ্যারে

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তীতে T সংখ্যক টেস্ট কেস থাকবে। প্রতিটি টেস্ট কেসের প্রথম লাইনে থাকবে একটি পূর্ণসংখ্যা n (n<=20), যেটি অ্যারের উপাদান নির্দেশ করে। এর পরের n সংখ্যক লাইনে n সংখ্যক অ্যারের উপাদান ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে অ্যারেটি সাজানো (sorted) কি না সেটি প্রিন্ট করতে হবে। যদি সাজানো হয় তাহলে প্রিন্ট করবে "YES" অন্যথায় "NO"।

ইনপুটআউটপুট
2
5
1
2
3
4
5
10
1
2
3
4
5
6
7
9
10
8
YES
NO
সমাধান দেখুন

সমাধান

একটি অ্যারে সর্টেড কি না সেটি আমরা কী করে বুঝব? আর সেটি ছোট থেকে বড় নাকি বড় থেকে ছোট ক্রমে সাজানো, সেটিই বা বুঝব কী করে?

এই সমস্যা সমাধানে নিচের ধাপগুলো অনুসরণ করা যেতে পারে:

  1. সব সংখ্যাগুলো একটি অ্যারেতে ইনপুট নাও।
  2. সংখ্যাগুলো ছোট থেকে বড় ক্রমে সাজানো কি না, সেটি বের করার চেষ্টা করো। যদি সাজানো থাকে, তাহলে YES প্রিন্ট করে দাও। আর যদি সাজানো না থাকে তাহলে পরের ধাপে যাও।
  3. সংখ্যাগুলো বড় থেকে ছোট ক্রমে সাজানো কি না, সেটি বের করার চেষ্টা করো। যদি সাজানো থাকে, তাহলে YES প্রিন্ট করে দাও। আর যদি সাজানো না থাকে তাহলে NO প্রিন্ট করে দাও।

আর সাজানো কি না সেটি পরীক্ষা করার সময় তোমাদের একটি ফ্ল্যাগ ভ্যারিয়েবল ব্যবহার করতে হবে। ছোট থেকে বড় সাজানো কি না, তা বোঝার কোডটি এ রকম:

int sorted = 1;
for(i = 1; j < n; i++)
{
    if (array[i] < array[i-1])
    {
        sorted = 0;
        break;
    }
}

সমস্যার সমাধান করে অনলাইন জাজে জমা দাও। আশা করি, উত্তর সঠিক হবে।

সমস্যা ২৯ – চিহ্ন পরিচয়

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে একটি করে ক্যারেক্টার ch ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে ch ক্যারেক্টারটি uppercase বা বড় হাতের বর্ণ হলে "Uppercase Character" প্রিন্ট করবে, ক্যারেক্টারটি lowercase বা ছোট হাতের বর্ণ হলে "Lowercase Character" প্রিন্ট করবে, অথবা যদি digit হয় তাহলে "Numerical Digit" প্রিন্ট করবে। অন্যথায় প্রিন্ট করবে "Special Character"।

ইনপুটআউটপুট
4
a
A
5
;
Lowercase Character
Uppercase Character
Numerical Digit
Special Character
সমাধান দেখুন

সমাধান

সমস্যাটি কম্পিউটার কিবোর্ডের বিভিন্ন চিহ্ন চেনার সমস্যা। যেমন: কম্পিউটারের কাছে 'A' এবং 'a' এ দুটি জিনিস আলাদা। 'A' হচ্ছে uppercase letter বা বড় হাতের বর্ণ এবং 'a' হচ্ছে lowercase letter বা ছোট হাতের বর্ণ। এছাড়াও আরও অন্যান্য চিহ্ন আছে যেমন: '@', '+', '&' এগুলোকে আমরা বলব special character।

সমস্যাটির ইনপুটের বর্ণনা আগের অন্যান্য সমস্যার মতোই। T সংখ্যক লাইনে ক্যারেক্টার ch ইনপুট নিতে হবে। এখানে ক্যারেক্টার ইনপুট নিব আমরা এভাবে:

scanf("%c", &ch);

এভাবে ইনপুট নিলে একটিমাত্র ক্যারেক্টার ইনপুট নেওয়ার সময় কোনো সমস্যা হয় না। সাধারণত দেখা যায়, ক্যারেক্টার ইনপুট নেওয়ার সময় তোমরা একটি সমস্যা দেখতে পাও, যে কিবোর্ডের enter বাটন চাপ দিলে সেটি ক্যারেক্টার ইনপুট নেয় এবং আউটপুটে ঝামেলা শুরু করে।

তোমরা বুঝতেই পারছ এই কোডটি কন্ডিশনাল লজিকের সাহায্যে করতে হবে। এখন নিশ্চয়ই তোমরা নিজেরা একটি ক্যারেক্টার ইনপুট নিয়ে কাজ করতে পারবে। আমি এখানে কোডটি আসকি ভ্যালুর সাহায্যে করেছি। আমাদের কোডটি হবে এমন:

#include<stdio.h>

int main ()
{
    char ch;
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf(" %c", &ch);
        if(ch >= 'a' && ch <= 'z')
        {
            printf("Lowercase character\n");
        }
        else if(ch >= 'A' && ch <= 'Z')
        {
            printf("Uppercase character\n");
        }
        else if(ch >= '0' && ch <= '9')
        {
            printf("Numerical Digit\n");
        }
        else
        {
            printf("Special character\n");
        }
    }
    return 0;
}

কোডটি লিখে অনলাইন জাজে জমা দাও। জমা দেওয়ার পর যদি Wrong Answer দেখায় তাহলে অবশ্যই কোডটিতে কোনো সমস্যা আছে। সেগুলো ঠিক করে আবার জমা দিয়ে দেখতে পারো।


সমস্যা ৩০ – যোগ্য সংখ্যা ১

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=1000), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক পূর্ণসংখ্যা N (N<=2⁶⁴-1) ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে N পারফেক্ট সংখ্যা হলে "Yes, N is a perfect number!" অন্যথায় "NO, N is not a perfect number!" প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
6 28 30
YES, 6 is a perfect number!
YES, 28 is a perfect number!
NO, 30 is not a perfect number!
সমাধান দেখুন

সমাধান

এই বইটির প্রথম দিকেই তোমরা ভাজক সম্পর্কে ধারণা পেয়েছ। সমস্যার বর্ণনায় বলা আছে যোগ্য সংখ্যা কী, সেটি সম্পর্কে ধারণা পেয়েছ। এই সমস্যার সমাধানে কোনো একটি সংখ্যা পারফেক্ট কি না, সেটি বের করতে হবে।

ইনপুটের ধারণা আগের সমস্যাগুলোর মতোই। টেস্ট কেস ইনপুট নিতে হবে, সেই ইনপুটের মান যত ততগুলো পূর্ণসংখ্যা ইনপুট নিতে হবে।

ইনপুটের বর্ণনা পড়ে তোমরা কী বুঝতে পারলে? এখানে আমাদের ভাজক বের করার পর সেগুলোর যোগফল বের করতে হবে। প্রাপ্ত যোগফল যদি আমাদের ইনপুট সংখ্যার সমান হয় তাহলে সেটি একটি Perfect Number বা যোগ্য সংখ্যা।

প্রথমে, আমরা সংখ্যাটি ইনপুট হিসেবে নিয়ে ফেলি।

scanf("%llu", &N);

এবার for লুপের সাহায্যে সংখ্যা N-এর ভাজকগুলো আমরা বের করব। আমাদের লুপের গঠনটা এমন হবে:

unsigned long int sum = 0;
for(i = 1; i < N; i++)
{
    if(N%i == 0)
    {
        sum += i;
    }
}

এখানে ভাজকগুলোর যোগফল বের করেছি। এই যোগফল sum যদি আমাদের দেওয়া ইনপুট N-এর সমান হয় তাহলে N-কে যোগ্য সংখ্যা হিসেবে প্রিন্ট করব। একটি কন্ডিশনাল লজিক ব্যবহার করতে হবে। আর লুপটি কিন্তু একটু ছোট করে ফেলা যায়, i < N কন্ডিশনের পরিবর্তে i <= sqrt_n ব্যবহার করে, যেখানে sqrt_n হচ্ছে N-এর বর্গমূল।

এই কোডটিতে একটি ভুল রয়েছে। এখানে N এর সর্বোচ্চ মান হতে পারে, 2⁶⁴-1। unsigned long int টাইপের সর্বোচ্চ সীমাও যত, N-এর মান তত পর্যন্ত হতে পারে। এখন for লুপে ভাজকগুলোর যোগফল বের করার সময় যোগফল sum-এর মানও অনেক বড় হতে পারে। 12-এর ভাজকগুলো হচ্ছে 1, 2, 3, 4 ও 6, যাদের যোগফল, 1 + 2 + 3 + 4 + 6 = 16। 12 কি না 12-এর থেকে বড়। এমন সংখ্যা যদি সর্বোচ্চ সংখ্যাটি হয়, তবে তার ভাজকের যোগফল unsigned long int টাইপের সীমার মধ্যে রাখা সম্ভব হবে না। তাই কোডটি তোমরা এমন ভাবে লিখবে যেন ভাজক বের করার সঙ্গে সঙ্গে যোগ করে ফেলবে এবং যোগফল যদি ইনপুট সংখ্যার চেয়ে বড় হয়ে যায় তাহলেই।

সমস্যা ৩১ – যোগ্য সংখ্যা ২

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক ধনাত্মক পূর্ণসংখ্যা N (N<=40000000) ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে 1 থেকে N পর্যন্ত সবগুলো যোগ্য সংখ্যা বা পারফেক্ট নাম্বার প্রিন্ট করতে হবে।

ইনপুটআউটপুট
2
100 500
6
28
-
6
28
496
সমাধান দেখুন

সমাধান

তোমরা যদি যোগ্য সংখ্যা ১ এর সমাধান ঠিকভাবে করে থাকো, তাহলে এই সমস্যার সমাধানও সহজে করে ফেলতে পারবে। কেবল এখানে একটি লুপ বেশি হবে। কোডটি লিখে ফেলো। আচ্ছা, আমিই পুরো কোড লিখে দিই। তবে কোডের কোনো অংশ ব্যাখ্যা করব না। নমুনা কোডের কিছু অংশ বুঝতে সমস্যা হতে পারে। নিজেরা চিন্তা করো।

#include<stdio.h>
#include<math.h>

int main()
{
    int T, i, N, num, sqrt_num, sum;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &N);
        for(num = 1; num <= N; num++)
        {
            sum = 1;
            sqrt_num = sqrt(num);
            for(i = 2; i <= sqrt_num; i++)
            {
                if (num % i == 0)
                {
                    sum = sum + i + num / i;
                }
            }
            if (sum == num)
            {
                printf("%d\n", num);
            }
        }
    }
    return 0;
}

প্রোগ্রাম চালাতে কি অনেক বেশি সময় নিচ্ছে? তুমি যদি 1 থেকে 40000000-এই সীমার মধ্যে যোগ্য সংখ্যা খুঁজে বের করার কাজটি ঠিকঠাক করতে পারো, তুমি দেখবে যে তুমি মাত্র পাঁচটি সংখ্যা পেয়েছ, যাদেরকে যোগ্য সংখ্যা বলা যাবে। সংখ্যাগুলো হচ্ছে 6, 28, 496, 8128, 33550336।

এখন তোমাদের একটি সহজ বুদ্ধি শিখিয়ে দিই। হয়তো এই বুদ্ধি কখনো কাজে লেগে যেতে পারে। আমরা একটি প্রোগ্রাম রান করে সংখ্যাগুলো বের করে ফেলার পর আরেকটি প্রোগ্রাম লিখব, যেখানে আমরা আমাদের জানা সংখ্যাগুলো ব্যবহার করব।

int ara[] = {6, 28, 496, 8128, 33550336};

তারপরে কেবল একটি লুপ চালিয়ে দেখব যে নির্দিষ্ট সীমার মধ্যে কোন কোন সংখ্যা আছে:

for(i = 0; i < 5; i++)
{
    if (ara[i] <= n)
    {
        printf("%d\n");
    }
    else
    {
        break;
    }
}

তোমরা এখন পুরো প্রোগ্রামটি লিখে ফেলো আর অনলাইন জাজে জমা দাও।

সমস্যা ৩২ – x-এর গুণিতক

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে দুটি করে পূর্ণসংখ্যা X এবং N (1<=X<=N<=1000000) ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে X থেকে N পর্যন্ত X এর গুণিতকসমূহ প্রিন্ট করতে হবে। যদি X এর মান N এর থেকে বড় হয় তাহলে "Invalid!" প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
2 10
99 1000
10 5
2
4
6
8
10

99
198
...
990

Invalid!
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় বলা আছে ইনপুট হবে একটি পূর্ণসংখ্যা T, যেটি আমাদের টেস্ট কেসের সংখ্যা। তাহলে আমাদের প্রথমে কাজ হবে ইনপুট নেওয়া। T এর জন্য ডেটা টাইপ নিব int

int T;

এরপর T সংখ্যক লাইনে ইনপুট নিতে হবে আরও দুটি পূর্ণসংখ্যা X এবং N। খেয়াল করে দেখো এখানে N ভ্যারিয়েবলটির জন্য একটি রেঞ্জ দেওয়া আছে। সেই রেঞ্জ এর সংখ্যা বিবেচনায় রেখে আমরা X এবং N এর জন্য int ডেটা টাইপ নিব।

int X, N;

এবার আমরা একটি লুপ চালাব যেটি T এর মান যত ততবার চলবে:

for(i = 0; i < T; i++) { }

লুপের মধ্যে প্রতিবার ইনপুট নিতে হবে X এবং N-এর মান:

scanf("%d %d", &X, &N);

এবার মূল কোডটি লেখার জন্য প্রথমে আমরা বিবেচনায় আনব Invalid এর কন্ডিশনটি। যদি Invalid কন্ডিশনটি সত্যি না হয় তখন আমরা 1 থেকে N পর্যন্ত একটি লুপ চালাব এবং তাদের ভেতর থেকে X এর গুণিতক বের করার কাজটি করব। 1 থেকে N এর মধ্যে যে সব সংখ্যা X দ্বারা নিঃশেষে বিভাজ্য। কোডটি হতে পারে এমন:

for(j = 1; j <= N; j++)
{
    if(j%X == 0)
    {
        printf("%d\n", j);
    }
}

আবার প্রোগ্রামটি চালিয়ে দেখো ঠিকমতো ফলাফল দিচ্ছে কি না। যদি ঠিকঠাক লিখে ফেলতে পারো তবে জমা দাও। আমরা একটি চিন্তা করে দেখি এই সমাধানটি হলো কি না। আমরা এখানে 1 থেকে N পর্যন্ত একটি লুপ চালিয়েছি। এখানে N এর মান সর্বোচ্চ হতে পারে 1000000। অর্থাৎ, এই লুপটি সর্বোচ্চ 1000000 বার চলবে।

প্রতি বারে আমাদের হিসাব করতে হচ্ছে সংখ্যাটি X এর গুণিতক কি না। মনে করো যদি j এর মান 1 এর বদলে X দিয়ে শুরু করি এবং প্রতি ধাপে এক এক করে না বাড়িয়ে একেবারে X এর সমান বাড়াই, তাহলে আমাদের অনেকগুলো ইটারেশন কমে যাবে। আর সেই সঙ্গে তখন if ব্যবহার করে পরীক্ষা করারও দরকার পড়বে না। কারণ, আমরা X এর মানের গুণিতক বের করছি। আর মান বৃদ্ধি করছি, তাই j এর মান সবসময় X এর গুণিতকই থাকবে।

for(j = X; j <= N; j = j + X)
{
    printf("%d\n", j);
}

এভাবে করা অনেক ক্ষেত্রেই কোডের রানটাইম কমিয়ে ফেলতে পারে। দুটি সমাধানই একই কাজ করছে, কিন্তু পরের সমাধানটি আগেরটির চেয়ে দ্রুত চলবে। এই যে, বুদ্ধি খাটিয়ে প্রোগ্রামের রানটাইম কমিয়ে ফেললাম, এই কাজটিকে আমরা বলি অপটিমাইজেশন। পরের কোডটি আগের কোডের চেয়ে অপটিমাইজড।

এখন তোমরা কোডটি গুছিয়ে লিখে ফেলো। প্রথমে কম্পাইল ও রান করবে। যেই নমুনা ইনপুট দেওয়া আছে, সেগুলো দিয়ে দেখবে যে নমুনা আউটপুটের সঙ্গে মিলে কি না। নিজে কিছু ইনপুট দিয়েও পরীক্ষা করতে পারো। তারপর এই সমস্যার লিঙ্কে গিয়ে সাবমিট করে দেখো।


সমস্যা ৩৩ – বিভাজনসাধ্য ১

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে তিনটি পূর্ণসংখ্যা A, B, C (1 <= A, B, C <= 1016) ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে A থেকে B পর্যন্ত যতগুলো সংখ্যা C দ্বারা নিঃশেষে বিভাজ্য সেই সংখ্যাগুলো প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
2 20 3
50 60 5
55 100 6
3
6
9
12
15
18

50
55
60

60
66
72
78
84
90
96
সমাধান দেখুন

সমাধান

খুবই সহজ একটি সমস্যা। তিনটি পূর্ণসংখ্যা A, B, C দেওয়া থাকবে। C দিয়ে A থেকে B পর্যন্ত যতগুলো সংখ্যা নিঃশেষে বিভাজ্য বের করতে হবে।

তোমরা বুঝতেই পারছ যে, এখানে A থেকে B পর্যন্ত আমাদের একটি লুপের দরকার হবে এবং আমরা লুপটি চালিয়ে সময় A থেকে B পর্যন্ত সংখ্যাগুলোকে C দিয়ে ভাগ করতে থাকব।

ইনপুটের বর্ণনার মতোই বলা আছে T সংখ্যক লাইনে ইনপুট নেওয়ার কথা। ইনপুট হবে তিনটি পূর্ণসংখ্যা A, B, C। মনে রাখবে, ভ্যারিয়েবলের নাম যথাযথ হওয়া বাঞ্ছনীয়। ধরো, এখানে আমি A, B, C না দিয়ে অন্য কোনো বা আমার পছন্দের নাম ব্যবহার করলাম (অনেক কিছু তোমরা এমনটি করো)। আউটপুটের কোনো সমস্যা না হলেও ইনপুট নেওয়ার পর যখন বুঝতে হবে যে, কোনটি দিয়ে কী করা হয়েছিল।

A থেকে B পর্যন্ত সব সংখ্যাগুলো পাওয়ার জন্য আমরা যে লুপ চালাব সেটি এমন:

for(i = A; i <= B; i++) { }

আমার কাজ শেষ। এখন A এবং B-এর মধ্যকার সংখ্যাগুলোকে C দিয়ে যে সংখ্যাগুলো নিঃশেষে ভাগ করা যায় সেগুলো প্রিন্ট করার কাজ তোমাদের। সমস্যাটি সমাধান করার পর চিন্তা করে দেখ দেখি, A, B, C এর সর্বোচ্চ মান কত হতে পারে এবং তোমার লুপটি কতবার চলবে। “x-এর গুণিতক” এর সমস্যায় যে অপটিমাইজেশন টেকনিক ব্যবহার করেছি, সেটি কি কোনোভাবে এই সমস্যায় ব্যবহার করা যায়?

সমস্যা ৩৪ – বিভাজনসাধ্য ২

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে তিনটি পূর্ণসংখ্যা A, B, C (1<=A, B<=10⁹ এবং C<=10¹⁶) ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে 1 থেকে C পর্যন্ত যতগুলো সংখ্যা A এবং B দিয়ে নিঃশেষে বিভাজ্য সেই সংখ্যাগুলো প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
2 3 50
3 5 50
5 6 100
6
12
18
24
30
36
42
48

15
30
45

30
60
90
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় বলা আছে তিনটি পূর্ণসংখ্যা A, B, C দেওয়া থাকবে। 1 থেকে C পর্যন্ত যতগুলো সংখ্যা A এবং B দিয়ে নিঃশেষে বিভাজ্য সেগুলো আউটপুটে দেখাতে হবে।

ইনপুটের বর্ণনার মতোই বলা আছে T সংখ্যক লাইনে ইনপুট নেওয়ার কথা। প্রথমে একটি ভ্যারিয়েবল নিতে হবে T, এটির সাহায্যে আমরা একটি লুপ চালাব এবং T-এর মান যত ঠিক ততটি লাইনে আমরা A, B, C ইনপুট নিব।

scanf("%d", &T);

এখানে আমরা for লুপের পরিবর্তে while লুপ দিয়েও কাজ করতে পারি। আমি এখানে while লুপ ব্যবহার করেছি। C-এর মান এক এক করে কমবে। লুপের ভেতরে আমরা A, B, C-এর মান নিব। C-এর মান বিবেচনায় আমরা সহজেই এখানে long int ব্যবহার করব:

while(T--)
{
    scanf("%ld %ld %ld", &A, &B, &C);
}

এবার কোডের মূল কাজটি করার পালা। আমাদের এখন আরও একটি লুপ চালাতে হবে যেটি 1 থেকে C পর্যন্ত চলবে এবং ওই সীমার মধ্যে যতগুলো সংখ্যা A এবং B দিয়ে নিঃশেষে বিভাজ্য সেটি প্রিন্ট করে দেখাবে। কোডটি হবে পারে এমন:

for(i = 1; i <= C; i++)
{
    if(i%A == 0 || i%B == 0)
    {
        printf("%ld\n", i);
    }
}

এখন চলে দেখি এই সমাধানটিকে আমরা অপটিমাইজেশন করতে পারি কি না। অবশ্যই তোমরা নিজেরা আগে চেষ্টা করবে। দেখবে কোনোভাবে কোডের রানটাইম কমানো যায় কি না। আমার সমাধানটি নিচে দেখবে। আর এর আগে এ রকম আরও দুটি সমস্যার সমাধান করেছি: “x-এর গুণিতক” ও “বিভাজনসাধ্য-১”। দুটি সমস্যাই ছিল একটি নির্দিষ্ট সীমার মধ্যে একটি সংখ্যার গুণিতকের তালিকা খুঁজে বের করা। তাই, আমরা খুব সহজেই ব্যবহৃত লুপটি এক এক করে না বাড়িয়ে একেবারে ওই সংখ্যার সমান করে বাড়িয়ে লুপের ইটারেশন সংখ্যা অনেক কমিয়ে ফেলতে পেরেছিলাম। কিন্তু এখানে সমস্যা হচ্ছে একেবারে দুটি সংখ্যারই গুণিতক বের করতে হবে। তাহলে আমরা এখন দুটি লুপ ব্যবহার করে দুটি সংখ্যার গুণিতক বের করে দেখব। আমরা আসলে যে সংখ্যাগুলো পাব সেগুলো দুটি গুণিতকের তালিকা। এখন দুটি তালিকা মিলিয়ে যে সংখ্যাগুলো পাব তা যদি গণিতের ভাষায় বলে তাহলে হবে দুটি সংখ্যার সাধারণ গুণিতক। তাহলে আমরা যদি দুটি সংখ্যার লঘিষ্ঠ সাধারণ গুণিতক বা ল.সা.গু. বের করে ফেলি তো তার গুণিতক বের করলে কিন্তু আমরা একই সমাধান পাব। আর এই সমাধানটি আগের সমাধানের চেয়ে অনেক দ্রুত চলবে। এবার তোমাদের কাজ হচ্ছে সম্পূর্ণ কোডটি ঠিকঠাক মতো লেখা এবং কোডে কোনো ভুল থাকলে সেটি বের করে ঠিক করা।

সমস্যা ৩৫ – বৃত্তের বাইরে

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক ইনপুট থাকবে। প্রতিটি ইনপুট প্রথম লাইনে থাকবে বৃত্তের কেন্দ্রের স্থানাঙ্ক (Xc, Yc), এরপর ইনপুট হবে বৃত্তের ব্যাসার্ধ r। পরে ইনপুট নিতে হবে একটি স্থানাঙ্ক (X, Y) (|X|, |Y|, |Xc|, |Yc| < 100000)।

আউটপুট

প্রোগ্রামটির আউটপুটে (X,Y) বিন্দুটি বৃত্তের ভেতরে থাকলে প্রিন্ট করতে হবে "The point is inside the circle" অন্যথায় প্রিন্ট করতে হবে "The point is not inside the circle"।

ইনপুটআউটপুট
2
1 1
4
10 -14

1 1
8
5 6
The point is not inside the circle
The point is inside the circle
সমাধান দেখুন

সমাধান

কোনো বিন্দু একটি বৃত্তের বাইরে না ভেতরে আছে, সেটি জানার জন্য প্রথমে বৃত্তের কেন্দ্র থেকে ওই বিন্দুর দূরত্ব বের করতে হবে। সেটি যদি বৃত্তটির ব্যাসার্ধের চেয়ে বেশি হয়, তাহলে বিন্দুটি বৃত্তের বাইরে, আর না হলে বৃত্তের ভেতরে।

দুটি বিন্দুর মধ্যে দূরত্ব বের করবে কী করে? বিন্দু দুটির স্থানাঙ্ক জানা থাকলে একটি সূত্রের সাহায্যেই সেটি বের করা যায়। একটি বিন্দুর স্থানাঙ্ক (x₁, y₁) ও অপর বিন্দুর স্থানাঙ্ক (x₂, y₂) জানা থাকলে তাদের মধ্যবর্তী দূরত্ব হচ্ছে:

√ (x₂ − x₁)² + (y₂ − y₁)²

সূত্রের ব্যাখ্যা জানার জন্য তোমরা হাইস্কুল বা কলেজের জ্যামিতি বইয়ের শরণাপন্ন হতে পারো।

এখন তোমাদের কেবল জানতে হবে যে math.h হেডার ফাইলে sqrt() নামক একটি ফাংশন আছে, যেটি দিয়ে বর্গমূল বের করার কাজটি করা যায়। বাকি কাজ খুব সহজ।


সমস্যা ৩৬ – শব্দ সাজানো

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক টেস্ট কেস থাকবে। প্রতিটি টেস্ট কেসের প্রথম লাইনে একটি পূর্ণসংখ্যা N (N<=20), পরবর্তী N সংখ্যক লাইনে ইনপুট হবে একটি করে স্ট্রিং S (S এর দৈর্ঘ্য 10000 এর বেশি নয়)।

আউটপুট

প্রোগ্রামটির আউটপুটে N-সংখ্যক স্ট্রিংকে আক্ষরিক ক্রমানুসারে প্রিন্ট করতে হবে। আউটপুটের শুরুতে এবং শেষে একটি করে '\n' প্রিন্ট করতে হবে।

ইনপুটআউটপুট
1
5
x-ray
apple
cat
bat
house
apple
bat
cat
house
x-ray
সমাধান দেখুন

সমাধান

শব্দ সাজানো সমস্যাটি স্ট্রিং কম্পেয়ারের তুলনায় একটি সহজ সমস্যা। এখানে আমাদের যে কাজটি করতে হবে সেটি হচ্ছে N সংখ্যক ইনপুট স্ট্রিংগুলোকে আক্ষরিক ক্রমানুসারে সাজাতে হবে, অর্থাৎ সর্ট করতে হবে। সমস্যাটির সমাধান করার জন্য আমরা N-সংখ্যক স্ট্রিংকে পরস্পরর সঙ্গে তুলনা করতে পারি। আমি এখানে বাবল সর্ট অ্যালগরিদমের সাহায্য নিয়েছি। সর্টিং অ্যালগরিদমটি হবে এমন:

for(i = 0; i < N; i++)
{
    for(j = i; j < N; j++)
    {
        if(strcmp(name[i],name[j]) > 0)
        {
            strcpy(temp,name[i]);
            strcpy(name[i],name[j]);
            strcpy(name[j],temp);
        }
    }
}

এখানে N হচ্ছে স্ট্রিংয়ের সংখ্যা। আমরা string.h হেডার ফাইলের দুটি ফাংশন strcmp() এবং strcpy() এর সাহায্য নিয়েছি। strcmp() দিয়ে দুটি স্ট্রিংলোকে কম্পেয়ার করা হচ্ছে এবং strcpy() দিয়ে আরেকটি স্ট্রিং ভ্যারিয়েবল temp-এ আমরা স্ট্রিং কপি করেছি। সাধারণত, আমরা দুটি সংখ্যা তুলনা করতে গেলে যেটি বড় বা ছোট, স্ট্রিংয়ের ক্ষেত্রে তুলনা করার সময় strcmp() ফাংশন ব্যবহার করে থাকি।

ওপরে কোডটুকু করার পর, স্ট্রিংগুলোকে প্রিন্ট করলে সেগুলো আক্ষরিক ক্রমানুসারে প্রিন্ট হবে। আউটপুটে দুটি নিউলাইন থাকবে। একটি ইনপুট সেট হওয়ার আগে এবং একটি ইনপুট সেট হওয়ার পরে।

এই কোডিংটুকু কিন্তু আমরা অপটিমাইজেশন করতে পারি। আমরা এখানে ছোট থেকে বড় আকারে সাজানোর জন্য বাবলসর্ট অ্যালগরিদম ব্যবহার করেছি। যদি আমরা আরও দ্রুত কোনো সর্টিং অ্যালগরিদম ব্যবহার করতে পারি তাহলে কোডটিও দ্রুত চলবে। তোমরা বিভিন্ন রকম অ্যালগরিদম শিখবে তখন সেই অ্যালগরিদমগুলোর মধ্যে এখানে সবচেয়ে উপযোগী সেটিই ব্যবহার করবে।

সমস্যা ৩৭ – সংখ্যা বিপর্যয়

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে একটি করে পূর্ণসংখ্যা N (N<=10000000) ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে N কে উল্টোভাবে প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
612
1431056
10041992
216
6501341
29914001
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় বলা আছে একটি সংখ্যাকে উল্টো করে প্রিন্ট করতে হবে। এর মানে হচ্ছে যদি একটি সংখ্যা হয় 123 তাহলে আমাদের দেখাতে হবে 321।

উদাহরণস্বরূপ: ধরা যাক, আমরা যে সংখ্যাটিকে উল্টো প্রিন্ট করতে চাইছি সেটি 123, অর্থাৎ N = 123। যদি আমরা 123-কে আমরা যদি 10 দ্বারা ভাগ করি তাহলে ভাগশেষ পাব 3 এবং ভাগফল পাব 12। ভাগশেষ 3 হচ্ছে আমাদের দেওয়া সংখ্যাটির শতকের ঘরের অঙ্ক এবং সব সংখ্যাটি উল্টো করলে আমরা এই অঙ্কটি প্রথমে পাব।

ইনপুটের বর্ণনায় বলা আছে যে, T-সংখ্যক লাইনে ইনপুট নিতে হবে একটি করে পূর্ণসংখ্যা। অর্থাৎ, T-এর মান যত ততগুলো সংখ্যা ইনপুট নিতে হবে এবং সেটিকে উল্টোভাবে প্রিন্ট করতে হবে।

এবার একটি হিসাব করা যাক এই 123 সংখ্যাটি নিয়ে।

আমরা দুটি ভ্যারিয়েবল নেই rev (reverse-এর জন্য) এবং N = 123। এই হিসাবে তিনটি ধাপ থাকবে।

  1. প্রথমে rev এর কোনো ভ্যালু থাকবে না, কারণ আমরা সংখ্যাটি উল্টে দেখিনি। তাহলে rev = 0
  2. 123 % 10 = 3, 123-কে 10 দিয়ে ভাগ করলে ভাগশেষ থাকবে 3। rev এর ভ্যালু 0 বলে rev = 3 হবে এখন।
  3. এবার N-এর ভ্যালু আপডেট করতে হবে। N = N/10; এখন N-এর ভ্যালু হবে N = 123/10 = 12

এই কাজটি যদি আমরা N-এর মান শূন্য না হওয়া পর্যন্ত বারবার করি তাহলে আমরা একসময় আমাদের কাঙ্ক্ষিত আউটপুট পেয়ে যাব। এর জন্য আমাদের কোডটি হবে এমন:

while(num != 0)
{
    rev = rev * 10;
    rev = rev + N%10;
    N = N / 10;
}

এই কোডটির ইটারেশন হবে এমন:

ধাপnum != 0revN
00123
1truerev * 10 = 0
rev + N%10
= 0 + 123 % 10
= 0 + 3 = 3
N / 10
= 123 / 10
= 12
2truerev * 10 = 30
rev + N%10
= 30 + 12 % 10
= 30 + 2 = 32
N / 10
= 12 / 10
= 1
3truerev * 10 = 320
rev + N%10
= 320 + 1 % 10
= 320 + 1 = 321
N / 10
= 1 / 10
= 0
4falsestopstop

আমরা প্রথম ধাপে 123 উল্টো করে পাওয়া প্রথম অঙ্ক 3 পেয়ে গেলাম। আমরা দ্বিতীয় ধাপে পেলাম rev = 32 এবং N = 1। আমরা তৃতীয় ধাপে পেলাম rev = 321 এবং N = 0। তোমরা কি খেয়াল করেছ যে আমরা rev-এর মানে আমাদের কাঙ্ক্ষিত আউটপুট পেয়ে গেছি এবং N এর মান শূন্য হয়ে গিয়েছে।

এখন তোমাদের কাজ হচ্ছে আউটপুট প্রিন্ট করে পুরো কোড লিখে অনলাইন জাজে জমা দেওয়া।

এবার তোমরা আরেকভাবে সমাধান করার চেষ্টা করতে পারো। সংখ্যাকে স্ট্রিংয়ে রূপান্তর করে স্ট্রিংটি উল্টে দেওয়া।

সমস্যা ৩৮ – হীরক রাজ্য

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100) ইনপুট নিতে হবে এবং পরবর্তী T সংখ্যক লাইনে দুটি পূর্ণসংখ্যা nm (1<=n<=40, 1<=m<=9) ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে 2n-1 সংখ্যক লাইনে m উপাদান দিয়ে হীরক আকৃতি প্রিন্ট করতে হবে। প্রতিটি আউটপুটের শেষে একটি করে নিউলাইন প্রিন্ট করতে হবে।

ইনপুটআউটপুট
2
3 1
5 2
1
1 1
1 1 1
1 1
1

2
2 2
2 2 2
2 2 2 2
2 2 2 2 2
2 2 2 2
2 2 2
2 2
2
সমাধান দেখুন

সমাধান

এই সমস্যাটি হঠাৎ দেখে একটি কঠিন লাগতে পারে। কিন্তু আসলে এটি বেশ সহজ একটি সমস্যা। তোমরা লুপের ব্যবহার দক্ষ হতে হবে। নেস্টেড লুপ দিয়ে সমস্যাটি সহজেই সমাধান করা যায়।

একটি হিন্টস দিয়ে দিই। ধরা যাক, তোমাকে নিচের মতো একটি আকৃতি প্রিন্ট করতে হবে:

1
11
111
11
1

এটি তুমি দুই ধাপে করতে পারো। প্রথম ধাপে নিচের অংশটুকু প্রিন্ট করবে:

1
11
111

পরের ধাপে বাকি অংশটুকু প্রিন্ট করবে:

11
1

বাকি কাজ আমি আর তোমার করে ফেলতে পারব। এটার সমাধান করতে গিয়ে নেস্টেড লুপ ছাড়াও তোমরা আরেকটি জিনিস লক্ষ করো। আমরা একটি হীরক আকৃতি প্রিন্ট করার জন্য দুই ধাপে কাজ করেছি। মাঝে মধ্যে কোনো কোনো সমস্যাকে যদি ছোট ছোট ভাগে ফেলতে পারি, তাহলে সমাধান অনেক সহজ হয়ে যায়।


সমস্যা ৩৯ – প্যালিনড্রোম

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100) ইনপুট নিতে হবে এবং পরবর্তী T সংখ্যক লাইনে ইনপুট হবে একটি করে স্ট্রিং S (S এর দৈর্ঘ্য 1000 এর বেশি নয়)।

আউটপুট

প্রোগ্রামটির আউটপুটে স্ট্রিংটি প্যালিনড্রোম কি না সেটি দেখাতে হবে। যদি প্যালিনড্রোম হয় তাহলে প্রিন্ট করতে হবে "Yes! It is Palindrome!" অন্যথায় প্রিন্ট করতে হবে "Sorry! It is not Palindrome!"।

ইনপুটআউটপুট
3
wow
string
civic
Yes! It is palindrome!
Sorry! It is not palindrome!
Yes! It is palindrome!
সমাধান দেখুন

সমাধান

তোমরা যদি সি প্রোগ্রামিং ভাষার কোনো বই পড়ে থাকো, তোমরা নিশ্চয়ই জানো কীভাবে একটি স্ট্রিংকে উল্টে দিতে হয়। মনে করো স্ট্রিংটি হয় abcd, উল্টো স্ট্রিংটি হবে dcba। এখন তোমাকে যেই স্ট্রিংটি দেওয়া হবে, সেই স্ট্রিংয়ের আরেকটি অ্যারে নিতে হবে। তারপর একটি লুপ ব্যবহার করে প্রথম অ্যারের শেষ উপাদানটি দ্বিতীয় অ্যারের প্রথম উপাদানে অ্যাসাইন করবে, প্রথম অ্যারের শেষের আগের উপাদানটি দ্বিতীয় অ্যারের দ্বিতীয় উপাদানে অ্যাসাইন করবে, এ রকম করে চলবে। তাহলে এই সমস্যার সমাধান করতে গেলে তোমার কোড কী রকম হবে?

int main()
{
    char string1[1001], string2[1001];
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%s", string1);
        // now reverse the string into string2
        if (strcmp(string1, string2) == 0)
        {
            printf("Yes! It is Palindrome!\n");
        }
        else
        {
            printf("Sorry! It is not Palindrome\n");
        }
    }
    return 0;
}

তোমরা কোডটি সম্পূর্ণ করে তারপর অনলাইন জাজে জমা দিয়ে দেখো। আশা করি উত্তর সঠিক হবে।

এখন তোমরা চাইলে একটি অ্যারে দিয়েও কাজটি করতে পারো। ধরা যাক, যে স্ট্রিংটি প্যালিনড্রোম কি না তা পরীক্ষা করবে, সেটিতে দশটি ক্যারেক্টার রয়েছে। একটি লুপ চালাবে যেটি প্রথম ক্যারেক্টারের সঙ্গে দশম ক্যারেক্টার, দ্বিতীয় ক্যারেক্টারের সঙ্গে নবম ক্যারেক্টার, তৃতীয় ক্যারেক্টারের সঙ্গে অষ্টম ক্যারেক্টার, এভাবে তুলনা করবে এবং কোনো জায়গায় অমিল পাওয়া যায়, তাহলে সরাসরি বলে দেবে যে এটি প্যালিনড্রোম নয়। আর যদি সবকিছুই মিলে যায়, তবে তা প্যালিনড্রোম। এখন তোমরা টপাটপ প্রোগ্রাম লিখে ফেলো। নতুনদের ঘণ্টাখানেকের মতো (বা আরও বেশি) সময় লাগতে পারে, তাতে হতাশ হয়ো না, এটিই স্বাভাবিক।

সমস্যা ৪০ – ধারার যোগফল ১

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100) ইনপুট নিতে হবে এবং পরবর্তী T সংখ্যক লাইনে দুটি পূর্ণসংখ্যা X, K (X<=10 এবং K<=6) দেওয়া হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে ওপরের সিরিজের ফলফল প্রিন্ট করতে হবে। এখানে "=" এর আগে ও পরের স্পেসটি লক্ষণীয়।

ইনপুটআউটপুট
2
5 2
2 5
3
2 10
5 10
10 5
Result = 31
Result = 63

Result = 2047
Result = 12207031
Result = 111111
সমাধান দেখুন

সমাধান

এটি একটি যোগফল নির্ণয়ের ধারা যেখানে দুটি ভ্যারিয়েবল X, K রয়েছে। এখানে X এর power বা শক্তি K। সমস্যাটির বর্ণনায় প্রথম লাইনে একটি পূর্ণসংখ্যা দেওয়া হলো হয়েছে। এখানে আমরা পূর্ণসংখ্যা হিসেবে নিব T। পরবর্তী T সংখ্যক লাইনে আরও দুটি পূর্ণসংখ্যা ইনপুট নিতে হবে X, K। যেহেতু পূর্ণসংখ্যা নিয়েছি এবং বলা আছে K এর সর্বোচ্চ মান 6, তাই এখানে আমাদের ডেটা টাইপ হবে int

int X, T, K;

প্রথমেই আমরা T সংখ্যক লাইনে ইনপুট নেওয়ার কাজটি করে ফেলি। এর জন্য আমরা scanf() ফাংশন ব্যবহার করে T এর জন্য ইনপুট নিব এবং T সংখ্যক ইনপুট নেওয়ার জন্য T পর্যন্ত একটি for লুপ ব্যবহার করব।

scanf("%d", &T);
for(int i = 0; i < T; i++)
{
    // এবার আমাদের এই লুপটির ভেতরে X এবং K এর ইনপুট নেওয়ার কাজটি করতে হবে।
    // এখানে scanf() ফাংশন ব্যবহার করে ইনপুটটি করব।
    scanf("%d %d", &X, &K);
}

এবার আসি মূল হিসাবনিকাশের কাজে। যেহেতু একটি ধারার একটি কাজ বারবার হতে থাকে তাই আমরা যখন ধারার অঙ্কটি করতে যাই, তখন তাকে আমরা একটি লুপের সাহায্য নিই। ধারার যোগফল বের করতে গিয়ে, X এর পাওয়ার এক এক করে বাড়ছে। তাহলে এখানে আমাদের একটি for লুপ চালাতে হবে যেটি K পর্যন্ত চলবে। লক্ষ করো:

xk-1 x x = xk

আমরা যদি লুপ চালানোর সময় xk-1 এর মান অন্য একটি ভ্যারিয়েবলে রেখে দিই, তাহলে প্রতিবার তার সঙ্গে x কে গুণ করলেই আমরা ধারার পরের পদটি পেয়ে যাব।

int sum = 1, power = 1;
for(int i = 1; i <= K; i++)
{
    power = power * X;
    sum += power;
}

এই কোডটি কি ঠিকমতো আউটপুট দিবে? না দিলে এর কোথায় সমস্যা আছে খুঁজে বের করো তো। লক্ষ করো, আমি sumpower এর মান 0 না দিয়ে শুরুতেই 1 দিয়েছি, আর লুপটি চালানোর সময়ও আমি i = 0; না করে i = 1; করেছি।

আরেকটি বিষয় বলে দেই তোমাদের, তোমরা যারা ইতিমধ্যেই বিভিন্ন গণিত সমস্যার সমাধান করেছ তারা নিশ্চয়ই pow() ফাংশনের সঙ্গে পরিচিত। pow() ফাংশনটি দুটি double টাইপের ডেটা রিটার্ন করে। xk-এর মান বের করার জন্য অনেকেই এই ফাংশন ব্যবহার করতে চাইবে। তবে এই ফাংশনটি ব্যবহার করা ঠিক হবে না। সাধারণত, যেসব সমস্যার পূর্ণসংখ্যা, সেগুলোর সমাধানে পারতপক্ষে double বা float ডেটা টাইপ ব্যবহার করা উচিত নয়। কারণটা নিশ্চয়ই তোমরা বুঝে ফেলেছ, সেটি হচ্ছে প্রিসিশন (Precision) সমস্যা। double বা float জাতীয় সংখ্যা যোগ, বিয়োগ, গুণ, ভাগের সময় সাধারণত দশমিকের পরে কিছু অঙ্ক বাদ হয়ে যায়। তাই, নিতান্ত দরকার না পড়লে এই ডেটা টাইপগুলো ব্যবহার করা হয় না।

আরও একটি বিষয় খেয়াল করো, প্রদত্ত ধারাটি একটি গুণোত্তর ধারা বা Geometric progression। তোমরা যারা, গুণোত্তর ধারার সঙ্গে পরিচিত তারা কিন্তু ধারার সমষ্টির সূত্র ব্যবহার করেও এই সমস্যাটি সমাধান করতে পারো।

এখন তোমরা কোডটি গুছিয়ে লিখে ফেলো। প্রথমে কম্পাইল ও রান করবে। যেই নমুনা ইনপুট দেওয়া আছে, সেগুলো দিয়ে দেখবে যে নমুনা আউটপুটের সঙ্গে মিলে কি না। নিজে কিছু ইনপুট দিয়েও পরীক্ষা করতে পারো। তারপর এই সমস্যার লিঙ্কে গিয়ে সাবমিট করে দেখো।

সমস্যা ৪১ – ধারার যোগফল ২

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে হবে একটি পূর্ণসংখ্যা n (n<=15)

আউটপুট

প্রোগ্রামটির আউটপুটে n পর্যন্ত ওপরের ধারাটির যোগফল প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
5
8
10
2.7083
2.7183
2.7183
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় একটি ধারা দেওয়া আছে, আমাদের কাজ হবে ধারাটির যোগফল বের করা। প্রোগ্রামটির ইনপুট হবে দুটি সংখ্যা। প্রথমে একটি পূর্ণসংখ্যা T এবং পরবর্তী T সংখ্যক লাইনে ইনপুট হবে আরও একটি পূর্ণসংখ্যা n, যেহেতু, n এর রেঞ্জ দেওয়া আছে 15, সেখানে int ডেটা টাইপটি যথেষ্ট হলেও যেহেতু আমাদের ফ্যাক্টরিয়াল নিয়ে কোডটিতে কাজ করতে হবে তাই আমরা n এর জন্য ডেটা টাইপ নিব long long int (15! বেশ বড় সংখ্যা!)।

int T;
long long int n;

এবার ইনপুট নেওয়ার পালা। যেহেতু T সংখ্যক লাইনে ইনপুট নিতে হবে তাই প্রথমে আমাদের ইনপুট নিতে হবে T। আমরা T এর মান ইনপুট নেওয়ার জন্য scanf() এর সাহায্য নিব এবং T সংখ্যকবার একটি for লুপ চালাব।

scanf("%d", &T);
for(int i = 0; i < T; i++) { }

ধারাটি খেয়াল করলে দেখবে যে এখানে n পর্যন্ত প্রতিটি ক্রমবর্ধমান সংখ্যাকে সেই সংখ্যার ফ্যাক্টরিয়াল দিয়ে ভাগ করা হয়েছে। তাহলে আমাদের প্রথম কাজ হবে ফ্যাক্টরিয়ালের জন্য একটি ফাংশন লিখে ফেলা। আমরা জানি, কোনো সংখ্যার ফ্যাক্টরিয়াল সেই সংখ্যাসহ তার আগের ধনাত্মক পূর্ণসংখ্যাগুলোর গুণফল। যেমন: 5 এর ফ্যাক্টরিয়াল 120 (1×2×3×4×5 = 120)। আমাদের ফাংশনটি হবে এমন:

long long int fact(long long int n)
{
    long long int i, product = 1;
    for(i = 1; i <= n; i++)
    {
        product *= i;
    }
    return product;
}

এবার আবার main() ফাংশনে লেখার কাজ। main() ফাংশনে T সংখ্যকবার n এর মান নিব এবং ধারার ফলফল প্রিন্ট করব। যেহেতু, ধারাটিতে ভাগ করার কাজ আছে তাই আউটপুট দেখানোর সময় আমাদের ভাগফল রাখার জন্য double বা float টাইপের ভ্যারিয়েবল ব্যবহার করতে হবে। প্রথমেই আমরা n ইনপুট নেওয়ার কাজটি করব scanf() ফাংশন ব্যবহার করে।

scanf("%lld", &n);

ধারাটি যেহেতু n পর্যন্ত চলবে, তাই আমরা এখন n এর মান পর্যন্ত একটি লুপ চালাব যেটি ধারাটির পুরো হিসাবটি করবে। আমাদের সাহায্য নিব।

for(long long int i = 1; i <= n; i++)

ধারাটি একটি যোগফল নির্ণয়ের ধারা, তাই ওই আমরা নতুন একটি ভ্যারিয়েবল "sum" এ ধারাটির ফলফল জমা রাখব। sum এর ডেটা টাইপ হবে double। এখানে আমরা i এর মানকে fact(i) দিয়ে ভাগ করে সেটি যোগ করতে থাকব n পর্যন্ত। আমাদের কোডটি হবে এমন:

double sum = 0.0;
for(i = 1; i <= n; i++)
{
    sum += ( (double)i / fact(i) );
}

লক্ষ করে দেখো, এখানে আমরা i এর মান double এ টাইপকাস্ট করেছি। কারণ। একটি পূর্ণসংখ্যা এবং sum এ আমরা দশমিক সংখ্যা হিসেবে রেখেছি। ডেটা টাইপের কারণে যেন না আসে সেজন্য এরূপ করা হয়েছে।

এবার আমরা printf() ফাংশনের সাহায্যে আউটপুট প্রিন্ট করলেই আমাদের কাজ শেষ। নমুনা আউটপুট খেয়াল করলে দেখবে যে এখানে আউটপুট দশমিকের পর চার ঘর পর্যন্ত প্রিন্ট করেছে। আমাদের প্রিন্ট statement হবে এমন:

printf("%.4lf\n", sum);

এখন তোমরা কোডটি গুছিয়ে লিখে ফেলো। প্রথমে কম্পাইল ও রান করবে। যেই নমুনা ইনপুট দেওয়া আছে, সেগুলো দিয়ে দেখবে যে নমুনা আউটপুটের সঙ্গে মিলে কি না। নিজে কিছু ইনপুট দিয়েও পরীক্ষা করতে পারো। তারপর এই সমস্যার লিঙ্কে গিয়ে সাবমিট করে দেখো।


সমস্যা ৪২ – ধারার যোগফল ৩

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে একটি পূর্ণসংখ্যা N (N<=50)

আউটপুট

প্রোগ্রামটির আউটপুটে n পর্যন্ত ওপরের সমীকরণটি প্রিন্ট করতে হবে।

ইনপুটআউটপুট
3
5
8
10
2^5 + 2^4 + 2^3 + 2^2 + 2 + 1
2^8 + 2^7 + 2^6 + 2^5 + 2^4 + 2^3 + 2^2 + 2 + 1
2^10 + 2^9 + 2^8 + 2^7 + 2^6 + 2^5 + 2^4 + 2^3 + 2^2 + 2 + 1
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় একটি সমীকরণ দেওয়া আছে, আমাদের কাজ হবে সমীকরণটির সমাধান করা। প্রোগ্রামটির ইনপুট হবে দুটি সংখ্যা। প্রথমে একটি পূর্ণসংখ্যা T এবং পরবর্তী T সংখ্যক লাইনে ইনপুট হবে আরও একটি পূর্ণসংখ্যা N। যেহেতু, N এর রেঞ্জ দেওয়া আছে 50, তাই আমরা ডেটা টাইপ নিব int

int T, N;

আমরা প্রথমে T এর মান ইনপুট নেওয়ার জন্য scanf() ব্যবহার করব এবং T সংখ্যক লাইনে ইনপুট নেওয়ার জন্য T পর্যন্ত একটি for লুপ ব্যবহার করব।

scanf("%d", &T);
for(int i = 0; i < T; i++) { }

সমীকরণটি খেয়াল করলে দেখতে পাবে, এখানে k এর মান N থেকে শুরু হয়ে 0-তে পৌঁছেছে। তাহলে আমরা একটি reverse লুপ দিয়ে আমাদের কাজটি করতে পারি। একটি লুপ চালাব যেটি N থেকে শুরু হয়ে এক এক করে কমে 0 তে পৌঁছাবে। এই কাজটি করার আগে আমাদের N এর মান ইনপুট নিতে হবে। N-এর সংখ্যক লাইনে ইনপুট নিতে হবে, তাই আমরা N এর প্রথম লুপটির ভেতরে।

scanf("%d", &N);
for(int k = N; k >= 0; k--) { }

এবার আমাদের মূল কোডটি লেখার পালা। আমাদের প্রতিটি k এর মানের জন্য প্রিন্ট করতে হবে 2k। কিন্তু যখন, k এর মান হয়ে যাবে 1 তখন আমরা 2¹ এর বদলে প্রিন্ট করব শুধু 2 আর যখন k এর মান হয়ে যাবে 0 তখন আমরা 2⁰ এর বদলে প্রিন্ট করব 1।

if(k == 1) printf("2");
else if(k == 0) printf("1");
else printf("2^%d", k);

এখন তোমরা কোডটি গুছিয়ে লিখে ফেলো। প্রথমে কম্পাইল ও রান করবে। যেই নমুনা ইনপুট দেওয়া আছে, সেগুলো দিয়ে দেখবে যে নমুনা আউটপুটের সঙ্গে মিলে কি না। নিজে কিছু ইনপুট দিয়েও পরীক্ষা করতে পারো। N এর মান যদি 1 অথবা 2 হয় তখন কি এই কোডটি সঠিক আউটপুট দেয়?

সমস্যা ৪৩ – হিসাব-কিতাব

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে হবে তিনটি পূর্ণসংখ্যা p, q, c (1<=p, q, c<=100)

আউটপুট

প্রোগ্রামটির আউটপুটে "Result" কথাটি প্রিন্ট করতে হবে। আউটপুটে "=" চিহ্নের আগের এবং পরের স্পেসটি লক্ষণীয়।

ইনপুটআউটপুট
3
2 3 3
2 10 5
50 2 3
Result = 2
Result = 4
Result = 1
সমাধান দেখুন

সমাধান

এই সমস্যাটি একটি গাণিতিক সমস্যা। সমস্যার বর্ণনায় বলা আছে প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T এবং পরবর্তী T সংখ্যক লাইনে p, q, c। যেহেতু বলা আছে (p, q, c <= 100), সেক্ষেত্রে আমরা p, q, c ভ্যারিয়েবলের ডেটা টাইপ হবে int

int p, q, c, T;

এবার ইনপুট নেওয়ার পালা। আমাদের প্রথম ইনপুট হবে T। এরপর T সংখ্যক লাইনে p, q, c নেওয়ার জন্য একটি লুপ চালাতে হবে T পর্যন্ত।

scanf("%d", &T);
for(int i = 0; i < T; i++)
{
    scanf("%d %d %d", &p, &q, &c);
}

সমীকরণে p এর power হচ্ছে q। power এর কাজটি করার জন্য আমরা এখানে math.h হেডার ফাইলের অন্তর্গত pow() ফাংশনটি ব্যবহার করি তাহলে কিন্তু কাজ হবে না। কেন হবে না? কারণ, pow() ফাংশনের রিটার্ন টাইপ হচ্ছে double টাইপের ওপর মডুলাস অপারেটর ব্যবহার করা যায় না। তাই এটিকে আমাদের ইন্টিজারে টাইপকাস্ট করতে হবে, যেটা মাঝে মধ্যে ত্রুটিপূর্ণ ফলাফল দিতে পারে (error-prone)। আমরা আগেও বলেছি যদি int ব্যবহার করে সমাধান করা যায় তবে আমরা চেষ্টা করব double বা float ব্যবহার না করার। তাই আমরা লুপ ব্যবহার করে এই পাওয়ারটির মান নির্ণয় করব।

int temp = 1;
for(int j = 1; j <= q; j++)
{
    temp *= p;
}

এবার আমরা temp কে c দিয়ে মডুলাস করব।

int res = temp % c;

এখন আউটপুট প্রিন্ট করার পালা।

printf("Result = %d\n", res);

এখানে খেয়াল করো, আমি আউটপুট প্রিন্ট করার সময় একটি নিউলাইন প্রিন্ট করেছি এবং আউটপুটের নির্দেশনা অনুযায়ী "=" চিহ্নের আগে পরে স্পেস ক্যারেক্টার দিয়েছি।

এই সমাধানে কিন্তু একটি ভুল আছে, বলা হয়েছে, p ও q এর সর্বোচ্চ সীমা হতে পারে 100। যখন, p = 100 এবং q = 100, তখন pq = 10200

এখন এই সংখ্যাটি তো int এর সর্বোচ্চ সীমার চেয়ে অনেক বড়। তাহলে এত বড় সংখ্যা আমরা int বা long long int দিয়েও রাখতে পারব না। এখানে গুণের ফল অনেক বড় হয়ে যাবে এবং ওভারফ্লো হবে। তাহলে এর সমাধান কী? এর জন্য আমাদের একটি বুদ্ধি শিখে নিই:

pq-1 = a (mod m) --- (1)
p = b (mod m) --- (2)
pq = a*b (mod m) --- [(1) ও (2) গুণ করে পাই]

ওপরের সমীকরণটি অনেকের কাছে কঠিন মনে হতে পারে। এর ব্যাখ্যায় কিছু নেই। এখানে বলা হয়েছে যে, pq-1 এর সঙ্গে p গুণ করলে যেমন pq পাওয়া যায়, তেমনি pq-1 কে m দিয়ে ভাগ করে পাওয়া ভাগশেষ, p কে m দিয়ে ভাগ করে পাওয়া ভাগশেষ গুণ করলেও, pq কে m দিয়ে ভাগ করার পরের ভাগশেষ পাওয়া যাবে। এই লাইনটি যদি সত্যি হয় তাহলে এর মানে দাঁড়ায় যে, আমরা যখনই গুণ করব তখনই মডুলাস করে ফেলব। তাহলে আমাদের গুণফল কখনো অনেক বড় হওয়ার সম্ভাবনা নেই।

এই সমাধানটিতে একটি অপটিমাইজেশনও করা সম্ভব। সেটি আমি করে দেব না। তবে দুটি বুদ্ধি তোমাদের শিখিয়ে দেব। খেয়াল করে দেখো pq এর মান নির্ণয় করার জন্য আমাদের যে লুপটি চালাতে হয়েছে, আর কি কম সময়ে pq এর মান নির্ণয় করা যায়? ধরা যাক, q এর মান যদি হয় 100 আমরা লিখতে পারি:

p100 = p50+50 = p50 . p50 = (p50)2

অর্থাৎ, দেখো আমরা যদি p50 এর মান বের করে ফেলি তাহলে কিন্তু ওই সংখ্যাটির বর্গ করলেই p100 এর মান পাওয়া যাবে। আরও 50 বার লুপ চালানোর দরকার পড়ে না। একইভাবে, p50 বের করার জন্য p25 এর মানকে বর্গ করলেই হয়। তাহলে তোমরা একটি বুদ্ধি তো পেয়েই গেলে। এখন কোডটি অপটিমাইজড করে ফেলো কি না? এই সমস্যায় যদিও p ও q এর সর্বোচ্চ সীমা খুবই কম (মাত্র 100) কিন্তু এই বুদ্ধি ব্যবহার করলে অনেক বড় পাওয়ারও খুব অল্প সময়ে গণনা করা যাবে।

সমস্যা ৪৪ – প্যাসকেলের ত্রিভুজ ১

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=20), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে একটি করে পূর্ণসংখ্যা N (N<=20) ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে N তম সারি পর্যন্ত প্যাসকেলের ত্রিভুজ প্রিন্ট করতে হবে।

ইনপুটআউটপুট
2
3
4
1
1 1
1 2 1

1
1 1
1 2 1
1 3 3 1
সমাধান দেখুন

সমাধান

সমস্যা বর্ণনায় যদি মনোযোগ দিয়ে পড়, তাহলে লক্ষ করবে যে প্রতি লাইনের সংখ্যাগুলো পরের লাইনের সংখ্যাগুলো তৈরি করা যায়। এটি অবশ্যি এদের মধ্যে একটি সম্পর্ক আছে। আর প্রথম লাইনে বাকি সব লাইনের প্রথম ও শেষের সংখ্যা হচ্ছে 1।

প্রথম দুটি লাইন বিশেষভাবে বিবেচনা করতে পারি। যে N-এর মান 1 হলে কী আউটপুট হবে এবং N-এর মান 2 হলে কী আউটপুট হবে, সেটি একটি কন্ডিশন দিয়ে পরীক্ষা করতে পারি। এখন যদি N-এর মান 2-এর চেয়ে বেশি হয়, তাহলে কী হবে? N-এর যেকোনো মানের জন্যই প্রথম ও শেষ সংখ্যা 1। আর অন্য যেকোনো সংখ্যা, ধরা যাক m-তম সংখ্যা, হচ্ছে আগের লাইনের (m-1)-তম সংখ্যা ও m-তম সংখ্যার যোগফল। বিষয়টি পরিষ্কার না হলে কাগজে একটু এঁকে দেখলেই বুঝতে পারবে। তাহলে N-তম লাইনের সংখ্যাগুলো বের করতে হলে আমাদের (N-1)-তম (অর্থাৎ আগের লাইনের) সংখ্যাগুলো জানতে হবে। আবার আগের লাইনের সংখ্যাগুলো জানতে হলে, সেটির আগের লাইনের সংখ্যাগুলো জানতে হবে।

ধরতে even-এর ভেতর 1, 1 রেখে দিলাম। even[0] = 1; even[1] = 1;। প্যাসকেলের ত্রিভুজের দিকে তাকালে দেখবে যে তৃতীয় লাইন। এখন আমি যদি তৃতীয় লাইনের সংখ্যাগুলো বের করতে চাই, তাহলে সেগুলো হবে odd অ্যারেতে রাখব। আমরা জানি যে odd অ্যারেতে তিনটি উপাদান থাকবে (কেন? প্যাসকেলের ত্রিভুজ দিকে আবার তাকাও)। প্রথম উপাদান সবসময়ই 1, তাহলে লিখে দিতে পারি যে odd[0] = 1; আর অন্য উপাদান হচ্ছে odd[1] = even[0] + even[1]

একটি লুপ চালিয়ে odd অ্যারের শেষ উপাদান বাদে বাকি উপাদানগুলো বের করব, আর লুপের শেষে odd অ্যারের শেষ উপাদান 1 অ্যাসাইন করে দিব। আর odd অ্যারেতে আমরা তৃতীয় লাইনের সংখ্যাগুলো পেয়ে গেলাম। তারপর এই odd অ্যারে থেকে আবার even অ্যারে তৈরি করব, যেখানে চতুর্থ লাইনের সংখ্যাগুলো থাকবে। তোমরা নিজেরা কোড করার চেষ্টা করো, তবে প্রোগ্রামিংয়ে একেবারে নতুনদের জন্য কাজটি একটু কঠিনই হবে।

int odd[21], even[21];
int i, j, N;

scanf("%d", &N);

even[0] = 1;
even[1] = 1;

for(i = 3; i <= N; i++)
{
    if(i % 2 == 0)
    {
        even[0] = 1;
        for (j = 1; j < i - 1; j++)
        {
            even[j] = odd[j - 1] + odd[j];
        }
        even[j] = 1;
    }
    else
    {
        odd[0] = 1;
        for (j = 1; j < i - 1; j++)
        {
            odd[j] = even[j - 1] + even[j];
        }
        odd[j] = 1;
    }
}

ওপরে কোডে তোমরা লক্ষ করো, আমি কন্ডিশনাল লজিক ব্যবহার করে নির্ণয় করেছি যে এখন odd থেকে even তৈরি করব নাকি even থেকে odd? আর ওপরের ও শেষের 1 সংখ্যাটি অ্যারেতে বসিয়ে দিয়েছি। খেয়াল কর। কোড ঠিকঠাক বোঝার পর তোমার একটি কোড লিখতে হবে, আর প্রিন্ট করার জন্য। এখন তোমাদের জন্য প্রশ্ন, কোন অ্যারে প্রিন্ট করবে? সেটি কীভাবে বুঝবে?


সমস্যা ৪৫ – প্যাসকেলের ত্রিভুজ ২

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=100000), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে একটি করে পূর্ণসংখ্যা N (N <= 50) ইনপুট নিতে হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে N তম সারি পর্যন্ত প্যাসকেলের ত্রিভুজ প্রিন্ট করতে হবে।

ইনপুটআউটপুট
2
3
4
1
1 1
1 2 1

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
সমাধান দেখুন

সমাধান

প্রথমেই তোমরা প্যাসকেলের ত্রিভুজ - ১ সমস্যার সমাধানের জন্য যে প্রোগ্রাম লিখেছ, সেটি আবার সাবমিট করো। এখানে দেখবে টাইম লিমিট শেষ হয়ে গেছে দেখাচ্ছে। মানে তোমার কোড চলতে বেশি সময় নিচ্ছে।

এখন, তোমরা একটি ব্যাপার খেয়াল করো। প্যাসকেলের ত্রিভুজের ১০ম লাইন প্রিন্ট করতে গেলে তৃতীয় লাইন থেকে শুরু করে ১০ম লাইন পর্যন্ত, অর্থাৎ ২০-তম লাইনে বের করতে হলেও আগের সব লাইনেই বের করতে হচ্ছে। এভাবে একই কাজ বার বার করা লাগছে। আর এই সমস্যার বর্ণনায় টেস্ট কেসের সংখ্যাও বেশি। তাই সময়ে কুলাচ্ছে না।

আমাদের যদি ৫০তম লাইন বের করতে হয়, তাহলে কিন্তু ৩ থেকে ৪৯তম লাইনের প্রতিটি লাইন বের করেই আসতে হবে। তো এই লাইনগুলো যদি আমরা একটি অ্যারেতে রেখে দিতে পারি, তাহলে কিন্তু আর বার বার হিসাব করা লাগবে না। কেবল কোন লাইনটি বের করতে হবে তা জানলে আমরা অ্যারে সেই লাইনটি বের করে দিতে পারব।

আমরা অ্যারের সেই লাইনটি বের করে দিতে পারব। তোমরা নিশ্চয়ই বুঝতে পারছ যে এখানে দুই মাত্রার অ্যারে (2D অ্যারে) ব্যবহার করতে হবে। কোডের মূল অংশ আমি লিখে দিলাম।

long long int pascal[51][51];
int i, j;

pascal[1][0] = 1;
pascal[2][0] = 1;
pascal[2][1] = 1;

for(i = 3; i <= 50; i++)
{
    pascal[i][0] = 1;
    for(j = 1; j < i - 1; j++)
    {
        pascal[i][j] = pascal[i-1][j-1] + pascal[i-1][j];
    }
    pascal[i][j] = 1;
}

এখন N-এর মান ইনপুট নিয়ে pascal[N] রো-টি প্রিন্ট করতে হবে। সবার শেষে কিন্তু অতিরিক্ত স্পেস থাকলে চলবে না।

এই পদ্ধতি বা টেকনিক যদি আয়ত্তে এনে ফেলতে পারো, তাহলে বিরাট সুবিধা। অনেক সমস্যাই তখন তোমাদের জন্য সমাধান করা সহজ হয়ে যাবে। তোমরা চিন্তা করো, কোনো সমস্যায় এ রকম আগেভাগে সবকিছু রেখে দেওয়া যায় কি না। যেমন ফ্যাক্টরিয়াল নির্ণয়, ফিবোনাচ্চি নাম্বার, কিংবা সিভ পদ্ধতিতে মৌলিক সংখ্যা বের করা - এসব সমস্যার কথা চিন্তা করতে পারো।

আরেকটি বিষয়। কোডে long long int ব্যবহার করেছি কারণ ইন্টিজার উপাদানের সর্বোচ্চ দৈর্ঘ্য 15 হতে পারে, মানে সংখ্যা 15টি অঙ্ক থাকতে পারে, যেটি ইন্টিজার টাইপের ভ্যারিয়েবলে ধারণ করা যাবে না। আর প্রিন্ট করার জন্য %lld ব্যবহার করতে হবে।

সমস্যা ৪৬ – ত্রিভুজের ক্ষেত্রফল

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=1000), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে তিনটি করে পূর্ণসংখ্যা a, b, c (1<=a, b, c<=100)। এখানে লক্ষণীয়, ত্রিভুজের যেকোনো দুই বাহুর যোগফল অবশ্যই তৃতীয় বাহু অপেক্ষা বড় হবে।

আউটপুট

প্রোগ্রামটির আউটপুটে ত্রিভুজের ক্ষেত্রফল "Area", যেটি দশমিকের পর ৩ ঘর পর্যন্ত প্রিন্ট করবে। এখানে '=' চিহ্নের আগের ও পরের স্পেসটি লক্ষণীয়।

ইনপুটআউটপুট
3
24 30 18
13 18 15
20 20 20
Area = 216.000
Area = 95.917
Area = 173.205
সমাধান দেখুন

সমাধান

ত্রিভুজের ক্ষেত্রফল বের করার সমস্যা এটি। একটি ত্রিভুজের তিন বাহুর দৈর্ঘ্য দেওয়া থাকলে ত্রিভুজটির ক্ষেত্রফল বের করার প্রোগ্রাম লিখতে হবে। এই সমস্যাটির সমাধান ত্রিভুজের ক্ষেত্রফলের সূত্র দিয়ে সমাধান করা যায়। সূত্রটি তোমরা নবম-দশম শ্রেণির গণিত বইতে পেয়ে যাবে। জানা না থাকলে বই থেকে দেখে নিতে হবে।

ইনপুটের বর্ণনায় বলা আছে T সংখ্যক লাইনে, a, b, c-এর ইনপুট নিতে হবে; যেখানে a, b, c প্রত্যেকটিই পূর্ণসংখ্যা।

scanf("%d", &T);
while(T--)
{
    scanf("%d %d %d", &a, &b, &c);
}

এখনো পর্যন্ত যদি তোমরা ত্রিভুজের ক্ষেত্রফলের সূত্রটি জানা না থাকো তাহলে আমি এখানে উল্লেখ করে দিচ্ছি:

অর্ধপরিসীমা, s = (a + b + c) / 2

area = √ s × (s − a) × (s − b) × (s − c)

সূত্রটিতে বর্গমূলের প্রয়োগ আছে তোমরা দেখতে পারছো। এর আগেও তোমরা বর্গমূল বের করে এসেছো। তাই এখানে আর বিস্তারিত কিছু দিলাম না।

আউটপুটে আমাদের ক্ষেত্রফল প্রিন্ট করতে হবে। সেজন্য আউটপুটের বর্ণনায় বলা না থাকলেও এখানে ক্ষেত্রফল এর জন্য double ডেটা টাইপ ব্যবহার করতে হবে।

সমস্যা ৪৭ – অ্যারের জোট

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (T<=1000), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তীতে T সংখ্যক ইনপুট কেস থাকবে। প্রতিটি ইনপুট কেসে দুটি করে লাইন থাকবে। প্রথম লাইনে একটি সংখ্যা n1 (1<=n1<=100) থাকবে এবং তারপরে n1 সংখ্যক পূর্ণসংখ্যা থাকবে। একইভাবে দ্বিতীয় লাইনে একটি সংখ্যা n2 (1<=n2<=100) থাকবে এবং তারপরে n2 সংখ্যক পূর্ণসংখ্যা থাকবে। দুটি অ্যারেতেই সংখ্যাগুলো ছোট থেকে বড় ক্রমে সাজানো থাকবে। অ্যারে দুটির উপাদান 100000-এর চেয়ে ছোট হবে।

আউটপুট

প্রতিটি ইনপুট কেসের জন্য একটি লাইনে n1+n2 সংখ্যক সংখ্যা আউটপুট দিতে হবে। যেখানে দুটি অ্যারের সবগুলো সদস্য থাকবে এবং সংখ্যাগুলো ছোট থেকে বড় ক্রমে সাজানো থাকবে।

ইনপুটআউটপুট
2
3 1 3 5
2 4 10
5 10 20 30 40 50
3 15 21 22
1 3 4 5 10
10 15 20 21 22 30 40 50
সমাধান দেখুন

সমাধান

দুটি সর্টেড (ছোট থেকে বড় ক্রমে) অ্যারে দেওয়া থাকবে, তোমার কাজ হচ্ছে অ্যারে দুটিকে যুক্ত করে একটি ক্রমানুসারে সাজানো অ্যারে তৈরি করতে হবে। প্রথমে তোমরা নিচের কোড দেখো, তারপর সমাধান অ্যালগরিদম লিখে ফেলো।

int main()
{
    int a[] = {1, 2, 4, 7, 9, 10};
    int b[] = {1, 2, 3, 4, 8, 9, 10};
    int c[20];
    int i = 0, j = 0, k = 0, n1 = 6, n2 = 8, n;

    while(1)
    {
        if (a[i] < b[j])
        {
            c[k] = a[i];
            k++;
            i++;
        }
        else
        {
            c[k] = b[j];
            k++;
            j++;
        }
    }
    n = k;
    printf("%d", c[0]);
    for(i = 1; i < n; i++)
    {
        printf(" %d", c[i]);
    }
    printf("\n");
    return 0;
}

আমি যতটুকু কোড লিখেছি, সেটি কেবল দেখানোর জন্য যে সমস্যার সমাধান কীভাবে করতে হবে। কোডে যে ভুল আছে, সেটি কিন্তু আমি ইচ্ছে করে দিয়েছি, যেন কাজ শুরু হয় ছোট থেকে শুরু করা যায়। আমার কোড অসম্পূর্ণ, তোমরা সেটি সম্পূর্ণ করবে। নইলে প্রোগ্রামিংয়ের আনন্দ কোথায়!

এখন তোমাদের জন্য আরেকটি সমস্যা। আমি যে সমস্যাটি যদি এমন শর্ত থাকত যে, দুটি অ্যারেতে যৌথভাবে হওয়ার পরে যেই অ্যারেটি তৈরি হবে, সেখানে কোনো সংখ্যা একাধিকবার থাকতে পারবে না, তাহলে সমাধান কী?


সমস্যা ৪৮ – নিখোঁজ সংখ্যা

ইনপুট

প্রোগ্রামটির প্রথম ইনপুট হবে একটি পূর্ণসংখ্যা T (1<=T<=100), যা টেস্ট কেসের সংখ্যা নির্দেশ করে। পরবর্তী T সংখ্যক লাইনে একটি করে পূর্ণসংখ্যা N (1<=N<=100000) ইনপুট নিতে হবে, যা অ্যারের উপাদান সংখ্যা নির্দেশ করে। পরবর্তীতে N-1 সংখ্যক অ্যারের উপাদান ইনপুট নিতে হবে। অ্যারের কোনো উপাদানই N-এর চেয়ে বড় হবে না।

আউটপুট

প্রোগ্রামটির আউটপুটে কোন অ্যারের কোন উপাদানটি নেই সেটি খুঁজে বের করতে হবে।

ইনপুটআউটপুট
2
7 2 1 4 6 5 3
9 9 4 5 8 6 1 7 2
7
3
সমাধান দেখুন

সমাধান

সমস্যার বর্ণনায় বলা আছে যে 1 থেকে N পর্যন্ত সংখ্যাগুলোর মধ্যে N-1টি সংখ্যা আছে, একটি নিখোঁজ। সেই নিখোঁজ সংখ্যাটি আমাদের বের করতে হবে। কীভাবে করব?

প্রথমে একটি অ্যারেতে সংখ্যাগুলো ইনপুট নেই:

scanf("%d", &N);
for(i = 0; i < N - 1; i++)
{
    scanf("%d", &ara[i]);
}

এবার 1 থেকে N পর্যন্ত প্রতিটি সংখ্যা অ্যারের মধ্যে খুঁজব। যেই সংখ্যাটি পাব না, সেটিই হচ্ছে নিখোঁজ। এজন্য নেস্টেড লুপ ব্যবহার করতে হবে।

for (i = 1; i <= N; i++)
{
    found = 0;
    for(j = 0; j < N - 1; j++)
    {
        if (i == ara[j])
        {
            found = 1;
        }
    }
    if (found == 0)
    {
        printf("Missing number: %d\n", i);
    }
}

তোমরা এখন কোডটি লিখে ফেলো। ঠিকঠাক কোড করে সাবমিট করলে দেখবে টাইম লিমিট (Time Limit Exceeded) দেখাচ্ছে। কোডটি আরও ইফিশিয়েন্ট করা যায়। তোমরা যদি একটু চিন্তা করো, দেখবে ওপরের কোডে দুই জায়গায় break ব্যবহারের সুযোগ রয়েছে। কোনো সংখ্যা অ্যারেতে খুঁজে পেলে আর লুপ চালানোর দরকার নেই। আর নিখোঁজ সংখ্যা খুঁজে পেলেও লুপ চালানোর দরকার নেই। তাই প্রয়োজনীয় জায়গায় break ব্যবহার করে তুমি প্রোগ্রামের রানটাইম অনেক কমিয়ে ফেলতে পারো। প্রোগ্রামটি ঠিক করে অনলাইন জাজে জমা দিয়ে দেখো।

এবার আমরা দ্বিতীয় একটি সমাধান দেখব। যেহেতু N-এর সর্বোচ্চ মান হতে পারে 100000, আমরা 100001 উপাদান ধারণ করতে পারে এমন একটি অ্যারে নেব। শুরুতে সব উপাদানে 0 করে দেব। তারপর যেই সংখ্যাগুলো ইনপুট নেওয়া হবে, অ্যারের সেই ইনডেক্সটিতে 1 অ্যাসাইন করব। যেমন ইনপুটে যদি 7 থাকে, তাহলে ara[7] = 1;। তারপর সবগুলো সংখ্যা ইনপুট নেওয়া শেষ হলে অ্যারেতে শুরু থেকে শেষ পর্যন্ত একটি লুপ চালিয়ে দেখব যে কোন ঘরটি 0 আছে। কেবলমাত্র একটি ঘরেই 0 থাকবে, আর সেই ঘরটিই হচ্ছে আমাদের নিখোঁজ সংখ্যা। এবার কোড লেখার পালা:

int ara[100001];
int i, N, num, missing;

scanf("%d", &N);
for(i = 1; i <= N; i++) ara[i] = 0;
for(i = 0; i < N; i++)
{
    scanf("%d", &num);
    ara[num] = 1;
}
for(i = 1; i <= N; i++)
{
    if(ara[i] == 0)
    {
        missing = i;
        break;
    }
}
printf("Missing number: %d\n", missing);

আশা করি, তোমরা কোড দেখে বুঝতে পেরেছ। এবার সম্পূর্ণ প্রোগ্রাম নিজে নিজে লিখে ফেলো আর অনলাইন জাজে জমা দাও।

আচ্ছা, কেউ কি অ্যারে ব্যবহার না করে সমাধান করতে পারবে? বইটিতে কয়েক ঘণ্টা চিন্তা করে দেখোই না, পারো কি না।

চিন্তা করে না পারলে আমি আবার힌্টস দিয়ে দিই। ধরা যাক 1 থেকে 10 পর্যন্ত সংখ্যাগুলোর মধ্যে একটি বাদে বাকি 9টি সংখ্যা দেওয়া আছে: 10, 3, 2, 9, 5, 8, 4, 7, 1। এখন 1 থেকে 10 পর্যন্ত সংখ্যাগুলোর যোগফল হচ্ছে 55। আর যে নয়টি সংখ্যা দেওয়া আছে, সেগুলোর যোগফল 49। 55 থেকে 49 বিয়োগ করলে থাকে 6, আর এই 6-ই হচ্ছে আমাদের নিখোঁজ সংখ্যা। তোমরা যারা ধারার যোগফল কীভাবে বের করতে হয় জানো, তাদের সমাধান লিখতে কোনো সমস্যা হওয়ার কথা নয়। আর যারা জানো না, তারা স্কুল গণিত বইতে দেখে নাও (নবম-দশম শ্রেণির বইতে আছে, সপ্তম শ্রেণির বইতেও থাকার কথা)।

দেখলে তো, একটি সমস্যা কতভাবে সমাধান করা যায়। কীভাবে রানটাইম কমিয়ে প্রোগ্রাম লেখা যায়। কীভাবে মেমরিও কম খরচ করে প্রোগ্রাম লেখা যায়। আসলেই প্রোগ্রামিংয়ের প্রতিটি বড়ই অর্থবহ!

সমস্যা ৪৯ – মৌলিক কি না

ইনপুট

ইনপুট ফাইলের প্রথম লাইনে থাকবে টেস্ট কেসের সংখ্যা T (T≤10), এরপরে T সংখ্যক লাইন থাকবে যাদের প্রতিটিতে একটি করে পূর্ণসংখ্যা N (2 ≤ N ≤ 10000000000) থাকবে।

আউটপুট

প্রতিটি টেস্ট কেসের জন্য, যদি N মৌলিক হয়, প্রথমে প্রিন্ট করবে N, তারপরে " is a prime"। স্ট্রিংটি কোনো কোটেশন ছাড়া হওয়া চাই। মৌলিক না হলে প্রথমে প্রিন্ট করবে N, তারপরে " is not a prime" প্রিন্ট কোনো কোটেশন ছাড়া প্রিন্ট করবে। নমুনা আউটপুট আরও বিস্তারিত দেখতে পারো।

ইনপুটআউটপুট
3
2
6
11
2 is a prime
6 is not a prime
11 is a prime
সমাধান দেখুন

সমাধান

তোমরা ইতিমধ্যেই কোনো সংখ্যা মৌলিক কি না, সেটি বের করা শিখে নিয়েছ। তোমরা প্রথমে করবে কী, সেই জ্ঞান প্রয়োগ করে এই সমস্যাটির সমাধান করে ফেলো। সমাধানটি বেশিরভাগ ক্ষেত্রেই অনলাইন জাজে টাইম লিমিট এরর দিবে। মানে আরও ইফিশিয়েন্ট সমাধান দরকার।

এই সমস্যার মূল চ্যালেঞ্জ হচ্ছে, যে সংখ্যাটি মৌলিক কি না বের করতে হবে, তার সর্বোচ্চ মান হতে পারে 10000000000। তাই আমাদের কিছু জ্ঞান-বুদ্ধি প্রয়োগ করতে হবে। তোমাদের যদি 'কম্পিউটার প্রোগ্রামিং ১ম খণ্ড' বইটি পড়া না থাকে, তাহলে তোমরা http://cpbook.subeen.com ওয়েবসাইটে গিয়ে মৌলিক সংখ্যা অধ্যায়টি পড়ে নিতে পারো, সেখানে বিস্তারিত আলোচনা আছে। তাহলে আমাদের সমাধানের দিকে কীভাবে অগ্রসর হব এবং কোন কাজটি কেন করছি, সেটি বুঝতে সহজ হবে।

10000000000 -এর বর্গমূল হচ্ছে 100000। তাই আমরা একটি অ্যারেতে 100000 পর্যন্ত সব মৌলিক সংখ্যা বের করে রেখে দেব। আর এই কাজটি করার জন্য আমরা সিভ মেথডের সাহায্য নেব। সিভের বিস্তারিত “কম্পিউটার প্রোগ্রামিং - ১ম খণ্ড” বইতে আছে।

তারপর আমরা ইনপুট নেওয়ার পর তখন সংখ্যাটি মৌলিক কি না, সেটি পরীক্ষা করব। প্রোগ্রামটির গঠন এ রকম হবে:

#include<stdio.h>
#include<math.h>

void find_prime_number(int prime_ara[], int n)
{
    // write code here
}

int main()
{
    int prime_ara[]; // এখানে যথাযথভাবে অ্যারের সাইজ উল্লেখ করতে হবে।
    int T, sqrt_n;
    long long int N;

    find_prime_number(prime_ara, sqrt_n);
    is_prime = 1;
    for(i = 0; prime_ara[i] <= sqrt_n; i++)
    {
        if (N % prime_ara[i] == 0)
        {
            is_prime = 0;
            break;
        }
    }
    if (is_prime == 1)
    {
        printf("%lld is a prime\n", N);
    }
    else
    {
        printf("%lld is not a prime\n", N);
    }
    return 0;
}

সমস্যা ৫০ – লেফট-রাইট

ইনপুট

প্রথম লাইনে একটি সংখ্যা T (1<=T<=100) থাকবে। T-এর মান যত, এর পরে ততগুলো লাইনে একটি করে স্ট্রিং থাকবে। প্রতিটি স্ট্রিংয়ে কোনো ডিজিট ব্যতীত অন্য কোনো ক্যারেক্টার পাশাপাশি থাকবে না। প্রতিটি ইনপুট স্ট্রিং এর দৈর্ঘ্য 50 বা তার কম হবে।

আউটপুট

প্রতিলাইনের জন্য সেই লাইনে দেওয়া স্ট্রিংকে নিয়ম অনুযায়ী পরিবর্তন করলে যে নতুন স্ট্রিং পাওয়া যাবে সেটি প্রিন্ট করতে হবে।

ইনপুটআউটপুট
5
0L7
4R5L9
71
8R4R0
34R92L6
007
45559
71
84400
3499226
সমাধান দেখুন

সমাধান

এই সমস্যার দুটি শর্তের কথা বলা আছে। একটি হচ্ছে স্ট্রিংকে L পেলে করতে হবে আর R পেলে কী করতে হবে। যদি সি ভাষায় সেটি অনুবাদ করি, তাহলে মূল কাজ দাঁড়ায়:

if(ara[i] == 'L') ara[i] = ara[i-1];
if(ara[i] == 'R') ara[i] = ara[i+1];

এখন তোমরা একটি লুপ চালিয়ে পুরো সমাধানটি লিখে ফেলো। প্রথম প্রচেষ্টায় অনেকের সমাধান ভুল হওয়ার সম্ভাবনা আছে। সেক্ষেত্রে তোমাদের লক্ষ করতে হবে যে অ্যারের ইনডেক্স ব্যবহার করার সময় কোথাও গণ্ডগোল করছ কি না।


সমস্যা ৫১ – খোঁজ দ্য সার্চ ১

ইনপুট

প্রথম লাইনে একটি সংখ্যা T (1<=T<=100) থাকবে। T-এর মান যত, এর পরে ততগুলো লাইনে দুটি করে স্ট্রিং থাকবে। প্রতিটি স্ট্রিংয়ের দৈর্ঘ্য 128 এর কম এবং স্ট্রিং দুটি একটি স্পেস দিয়ে আলাদা।

আউটপুট

প্রতিলাইনের জন্য সেই লাইনের দ্বিতীয় স্ট্রিংটি প্রথম স্ট্রিংয়ে সর্বপ্রথম কোথা থেকে শুরু হয়েছে তা বলতে হবে।

ইনপুটআউটপুট
4
banana ana
banana ban
aquickbrownfoxjumpsoverthelazydog fox
foobar foobar
1
0
11
0
সমাধান দেখুন

সমাধান

বেশ সহজ একটি সমস্যা, সমাধানও সহজ। ধরা যাক তোমার প্রথম স্ট্রিংটি হচ্ছে str1 এবং দ্বিতীয় স্ট্রিংটি হচ্ছে str2-তে। এখন str2 এর প্রথম ক্যারেক্টার, অর্থাৎ str2[0]-কে str1 এর মধ্যে খোঁজা শুরু করবে। যদি খুঁজে পাও, তাহলে পরবর্তী ক্যারেক্টারগুলো মিলে কি না, সেটি পরীক্ষা করতে হবে। যদি মিলে যায়, তখনই ঘোষণা করে দিবে যে দ্বিতীয় স্ট্রিংটি প্রথম স্ট্রিংয়ে সর্বপ্রথম কোথা থেকে শুরু হয়েছে তা বলতে হবে।

str1_len = strlen(str1);
str2_len = strlen(str2);

for (i = 0; i < (str1_len - str2_len); i++)
{
    if (str2[0] == str1[i])
    {
        for (j = 1; j < str2_len; j++)
        {
            if (str2[j] != str1[i+j]) break;
        }
        if (j == str2_len)
        {
            printf("%d\n", i);
            break;
        }
    }
}

ওপরের কোড আমি প্রতিটি লাইন ধরে ধরে ব্যাখ্যা করলাম না। তোমাদের বুঝতে একটু সময় লাগতে পারে তবে মনোযোগ ও সময় দিলে অবশ্যই বুঝতে পারবে। না বুঝে কোড লিখে সেটি অনলাইন জাজে অ্যাকসেপ্ট করিয়ে কোনো লাভ হবে না, তাতে তুমি অরিজিনাল জম্পেশ হবে।

সমস্যা ৫২ – খোঁজ দ্য সার্চ ২

ইনপুট

প্রথম লাইনে একটি সংখ্যা T (1<=T<=100) থাকবে। T-এর মান যত, এর পরে ততগুলো লাইনে দুটি করে স্ট্রিং থাকবে। প্রতিটি স্ট্রিংয়ের দৈর্ঘ্য 128-এর কম এবং স্ট্রিং দুটি একটি স্পেস দিয়ে আলাদা।

আউটপুট

প্রতিলাইনের জন্য সেই লাইনের দ্বিতীয় স্ট্রিংটি প্রথম স্ট্রিংয়ে কতবার আছে তা বলতে হবে।

ইনপুটআউটপুট
5
banana ana
banana anna
aquickbrownfoxjumpsoverthelazydog fox
ddddd ddd
foobar foobar
2
0
1
3
1
সমাধান দেখুন

সমাধান

আমরা যখন বইয়ের একেবারে শেষ সমস্যায় চলে এসেছি। তোমরা নিশ্চয়ই এতক্ষণে প্রোগ্রামিং সমস্যার সমাধানের মজা পেয়ে গিয়েছ। আশা করি, অনেকেই এই সমস্যার সমাধানও নিজে নিজে করে ফেলেছ।

খোঁজ দ্য সার্চ ১ সমস্যাটির সমাধান যদি তুমি করে থাকো, তাহলে এটি তোমার জন্য সহজ হবে বৈকি। আর ওই সমস্যার সমাধান না থাকলে আমার পরামর্শ হবে ওটি আগে সমাধান করা।

খোঁজ দ্য সার্চ ১-এর সমাধান করার সময়, আমরা সাবস্ট্রিং পেয়েছিলাম, আমরা লুপ থেকে বের হয়ে গেছি। কারণ আমাদের দরকার ছিল সাবস্ট্রিং প্রথম কোন ঘর থেকে শুরু হয়েছে। আর এখন আমাদের দরকার হচ্ছে সাবস্ট্রিং মোট কতবার আছে। তাই একটি count ভ্যারিয়েবল ব্যবহার করতে হবে (int টাইপের) যার মান প্রথমে 0 করে দেব। সাবস্ট্রিং পেলে আমরা ভ্যারিয়েবলের মান এক এক করে বাড়াব এবং লুপ থেকে বের হব না। লুপটি যখন নিজে নিজে বন্ধ হবে, তখন আমরা count-এর মান প্রিন্ট করব। প্রোগ্রামটি নিজে নিজে লিখতে পারো। কারণ ক্ষেত্র count-এর মান কোন জায়গায় শূন্য সেট করবে সেটা বের করতে একটু সমস্যা হতে পারে, কিন্তু লেগে থাকলে সমাধান হবেই!

পরিশিষ্ট

অনলাইন জাজ কী এবং কেন?

গণিত অলিম্পিয়াড বা এই জাতীয় প্রতিযোগিতার সঙ্গে প্রোগ্রামিং প্রতিযোগিতার একটি বড় পার্থক্য হচ্ছে অনলাইন জাজ। প্রোগ্রামিং প্রতিযোগিতায় সাধারণত বিচারক-যাচাই ও মূল্যায়ন করা হয়ে থাকে শিক্ষার্থীদের দিয়ে। কিন্তু প্রোগ্রামিং প্রতিযোগিতায় তোমার উত্তর হলো কি না, তা যাচাই করার দায়িত্বটি কম্পিউটারের ওপর দেওয়া হয়, আর প্রোগ্রামকেই বলে অনলাইন জাজ। তুমি যখন প্রোগ্রামিং সমস্যার সমাধান তৈরি করবে, তখন সেই সমাধানটি অনলাইন জাজে জমা (submit) দিতে হবে।

অনলাইন জাজ তোমার সমাধানটি গ্রহণ করার পর বিভিন্ন ধরনের ফলাফল আসতে পারে তার একটি বিবরণ এখানে দেওয়া হলো:

  1. রং আনসার (Wrong Answer) – অনলাইন জাজে সাবমিট করা সমাধানের আউটপুট প্রোগ্রামের স্ট্যান্ডার্ড আউটপুটের সঙ্গে না মিললে এই ধরনের উত্তর আসে। পরে এ সংক্রান্ত বিস্তারিত আলোচনা করা হয়েছে।
  2. টাইম লিমিট এক্সিডেড (Time Limit Exceeded) – সাধারণত প্রত্যেকটি প্রোগ্রামের জন্য একটি নির্দিষ্ট সময় বেঁধে দেন। অর্থাৎ, সমাধানটি এমন হতে হবে যে, নির্দিষ্ট সময়ের মধ্যেই প্রয়োজনীয় আউটপুট তৈরি করে। যদি প্রোগ্রামটি চলতে এর চেয়ে বেশি সময় নেয়, তখন অনলাইন জাজ এই ধরনের ফলাফল তৈরি করে। এক্ষেত্রে বুঝতে হবে যে, কোডটিতে যে ধরনের অ্যালগরিদম ব্যবহার করেছ অথবা সমস্যাটি ভিন্নভাবে সমাধান করতে হবে।
  3. মেমরি লিমিট এক্সিডেড (Memory Limit Exceeded) – কিছু কিছু সমস্যার সমাধানের মেমরির বা RAM-এ কত জায়গা ব্যবহার করতে পারবে তার ওপরও একটি সীমা বেঁধে দেওয়া হয়। যদি সমাধানটি তারচেয়ে বেশি মেমরি ব্যবহার করে তখন সাধারণত এই ধরনের ফলাফল আসে।
  4. প্রেজেন্টেশন এরর (Presentation Error) – এই ফলাফলের অর্থ হচ্ছে আউটপুটের সবগুলো সঠিক হয়েছে, তবে উপস্থাপনা ঠিক নেই যে ফরম্যাটে আউটপুট দিতে বলা হয়েছে, তা অনুসরণ করা হয়নি। অর্থাৎ, হয়তো প্রয়োজনের চেয়ে বেশি বা কম স্পেস, নিউলাইন ('\n') ইত্যাদি ক্যারেক্টার প্রিন্ট করা হয়েছে।
  5. কম্পাইলেশন এরর (Compilation Error) – যদি সমাধানটি অনলাইন জাজে সঠিকভাবে কম্পাইল করতে না পারে, তখন এ ধরনের এরর দেওয়া হয়। এ রকম এরর পেলে বুঝতে হবে যে, কোডের কোথাও কোনো ত্রুটি রয়েছে, যেমন: সেমিকোলন-কমা ঠিক মতো না দেওয়া বা বিভিন্ন রকম বানান সঠিকভাবে না করা, ভ্যারিয়েবল ডিক্লেয়ার না করেই ব্যবহার করা ইত্যাদি।
  6. রানটাইম এরর (Runtime Error) – যদি সমাধানটি কোনো রকম সমস্যা বা এক্সেপশন তৈরি করে বন্ধ হয়ে যায়, তখন এই ধরনের ফলাফল দেওয়া হয়। কখনো কখনো অ্যারের ইনডেক্স ভুল হলে বা ভুল অ্যাড্রেস পয়েন্টার ব্যবহার করলে এই এরর হতে পারে।
  7. রেস্ট্রিকটেড ফাংশন (Restricted Function) – অনেক ক্ষেত্রে অনলাইন জাজে বিশেষ কিছু ফাংশন ব্যবহার নিষিদ্ধ থাকে। সাধারণত যদি ওইসব ফাংশন ব্যবহার করা হয় এ ধরনের ফলাফল দেওয়া হয়।
  8. আউটপুট লিমিট এক্সিডেড (Output Limit Exceeded) – যদি জমা দেওয়া সমাধানটি চলার সময় অতিরিক্ত আউটপুট দিতে থাকে, তখন এই ফলাফল দেওয়া হয়। ধরা যাক, কেউ যদি ভুলক্রমে একটি ইনফিনিট লুপ ব্যবহার করে আউটপুট দিতে থাকে তখন এই ফলাফল দেখা যাবে।
  9. অ্যাকসেপ্টেড (Accepted) – যদি সাবমিট করা সমাধানটি চলার পরে ওপরের কোনো ত্রুটি না হয় এবং তার তৈরিকৃত আউটপুট প্রোগ্রামের সেটের আউটপুটের সঙ্গে মিলে যায় তখন এই ফলাফল দেওয়া হয়। এর অর্থ হচ্ছে, জমা দেওয়া সমাধানটি সম্পূর্ণ সঠিক হয়েছে।

রং আনসার (Wrong Answer)

যারা বিভিন্ন প্রোগ্রামিং সমস্যায় সাধারণত ওয়েবসাইটে কোড জমা শুরু করেছ, তাদের জন্য সবচেয়ে সাধারণ ব্যাপার হচ্ছে এই রং আনসার (Wrong Answer)। “স্যাম্পল ইনপুট-আউটপুটের সঙ্গে তো আমার মিলে, তাহলে অনলাইন জাজ কেন রং আনসার দিচ্ছে?”

নমুনা ইনপুট-আউটপুট (Sample Input-Output) মিললেই হবে না। ধরা যাক, কোনো একটি মৌলিক সংখ্যা বের করার প্রোগ্রাম ইনপুট দেওয়া আছে 3, 5, 7 এর জন্য আউটপুট হচ্ছে প্রাইম। এখন এটা দেখে কেউ যদি এমন প্রোগ্রাম লেখে যে বিজোড় সংখ্যা মাত্রই প্রাইম, তাহলে তো হবে না, তাই না? তাই নিজে নিজে টেস্ট কেস তৈরি করে আগে নিজে পরখ করতে হবে যে আউটপুট কী হবে। তারপরে প্রোগ্রামের আউটপুটের সঙ্গে মিলিয়ে দেখবে।

আরেকটি ব্যাপার হচ্ছে ফরম্যাটিং। প্রতিটি টেস্ট কেসের শেষে নিউলাইন ('\n') দিতে হবে, যেটা অনেক সময় দেওয়া থাকে না। আর দেখতে হবে যে নমুনা আউটপুটের সঙ্গে যেন হুবহু মিলে। ছোটহাতের-বড়হাতের অক্ষর (Uppercase / lowercase) এবং স্পেস ক্যারেক্টার ঠিকমতো দিতে হবে। যেমন প্রোগ্রামের আউটপুটে যদি Case লিখতে বলা হয় আর তুমি যদি case লিখ, তাহলে হবে না। আবার Case 1: লিখতে বললে তুমি যদি Case 1 : লিখ (এর আগে একটি স্পেস), তাহলেও রং আনসার।

কখনো টেস্ট কেসটি করতে হবে। যেটা তোমাকে বলা হলো, a" এর মান বের করতে। এখন তুমি যদি খুব সহজেই কাজটি করে ফেলো। স্যাম্পল আউটপুট তো মিলেই, তুমি নিজেও যেসব ইনপুট-আউটপুট করে টেস্ট করলে, সেগুলোও মিলে যায়। কিন্তু এখানে n-এর মান 0 হলে কী হবে? আর ঋণাত্মক হলেই বা কী হবে? এগুলোও কিন্তু তোমার প্রোগ্রাম ঠিকঠাক আউটপুট দিতে হবে।

আরেকটি কমন হচ্ছে ফ্লোটিং পয়েন্ট সংখ্যা হিসেবে ঝামেলা হয়। সবকিছু ঠিকঠাক থাকলেও প্রতিটি ক্যালকুলেশনের সময় রং আনসার পেতে পারো। তাই এই কাজটি ঠিকঠাক করতে হবে। একটি উদাহরণ দিচ্ছি (নিজেই কোড):

>>> 2.1 - 1.9
0.20000000000000018

তাই ফ্লোটিং পয়েন্ট নিয়ে কাজ করার সময় সাবধান!

আরেকটা কারণ হচ্ছে ভুল অ্যালগরিদম ব্যবহার। এটাও আসলে সমস্যার বর্ণনা ঠিকভাবে বুঝতে না পারার ফলেই ঘটে থাকে।

এসব সমস্যা থেকে পরিত্রাণ পাওয়ার উপায় হচ্ছে রং আনসার পেলে সেটি যে তোমারই ভুল, এটা স্বীকার করে নেওয়া (মাঝে-মধ্যে জাজেরও ভুল হতে পারে, সেটা খুবই কম ঘটে)। নিজে আরও চিন্তাভাবনা করা, না পারলে বন্ধুদের সঙ্গে আলাপ করা। তাতেও কাজ না হলে অনলাইন ফোরামে পোস্ট দেওয়া যেতে পারে এ রকম সমস্যায় পড়েছে কি না এবং কীভাবে সমাধান হয়েছে।

প্রোগ্রামিং চর্চার কয়েকটি অনলাইন জাজ

অনেক ওয়েবসাইট আছে যেখানে প্রোগ্রামিং সমস্যা দেওয়া আছে এবং সেগুলোর সমাধান জমা দিলে স্বয়ংক্রিয়ভাবে বলে দেওয়া হয় যে সমাধানটি সঠিক হয়েছে কি না। প্রোগ্রামিং শিখতে যেহেতু চর্চা সবচেয়ে জরুরি, তাই অনলাইন জাজগুলো অনেক গুরুত্বপূর্ণ। এ রকম বেশকিছু অনলাইন জাজ ওয়েবসাইটগুলোর লিঙ্ক দিয়ে দিচ্ছি, এর বাইরেও আরও অনেক আছে।

  1. http://cpbook.subeen.com/p/blog-page_11.html: এখানে বাংলায় বেশ কিছু প্রোগ্রামিং সমস্যা দেওয়া আছে, যেগুলোর একেবারে যারা নতুন, তাদের জন্য ভালো।
  2. http://lightoj.com: এটি তৈরি করেছেন বাংলাদেশের জেন ফাইয়াজ। এখানে অনেক অভিজ্ঞ প্রোগ্রামারদের সঙ্গে বিগিনারদের জন্যও কিছু সমস্যা দেওয়া আছে।
  3. http://projecteuler.net: এখানে অনেক মজার মজার সমস্যা আছে যেগুলো বেশিরভাগই গণিত লিখে সমাধান করতে হয়। এখানে প্রোগ্রাম জমা দেওয়া লাগে না, কেবল প্রোগ্রাম দিয়ে বের করা উত্তরটি জমা দিতে হয়।
  4. http://train.usaco.org/usacogate: এটি যদিও আমেরিকার ইনফরমেটিক্স অলিম্পিয়াড ট্রেনিং প্রোগ্রাম, কিন্তু সাইটে যেকোনো দেশের প্রোগ্রামাররাই রেজিস্ট্রেশন করে অনুশীলন করতে পারে। তোমরা যারা প্রোগ্রামিং প্রতিযোগিতায় ভালো করতে চাও, তাদের অবশ্যই এখানে অনুশীলন করা উচিত।
  5. https://www.topcoder.com/: এখানে নিয়মিত অনলাইন প্রোগ্রামিং প্রতিযোগিতা অনুষ্ঠিত হয়। এখানে ভালো ফলাফল করলে ভালো চাকরিও দেওয়া হয় (কী আনন্দ!)। এ ছাড়া এখানে অনেক ভালো টিউটোরিয়াল ও আর্টিকেল আছে। এটি অভিজ্ঞ প্রোগ্রামারদের জন্য বেশ ভালো একটি সাইট।
  6. https://uva.onlinejudge.org/index.php: এই সাইটে নিয়মিত অনলাইন প্রোগ্রামিং প্রতিযোগিতার আয়োজন করা হয়। এছাড়াও অনুশীলনের জন্য সমস্যা দেওয়া আছে। নতুন প্রোগ্রামারদের জন্য এটি বেশ ভালো জায়গা। তবে এই ধরনের অনেক প্রবলেম আছে। তাই খেয়াল রাখতে হবে কোন প্রবলেম সলভ করতে সময় নষ্ট না হয়।
  7. http://www.spoj.com/: এখানে অনেক ভালো সমস্যা আছে। সমাধান করে প্রোগ্রাম জমা দিলে প্রোগ্রাম কি না তা জানা যায়। এই ওয়েবসাইটের একটি বৈশিষ্ট্য হচ্ছে সি, সি প্লাস প্লাস, জাভা, পার্ল, পাইথন, রুবি, পিএইচপি এ রকম আরও অনেক ল্যাঙ্গুয়েজ ব্যবহার করে প্রোগ্রাম লেখা যায়।
  8. http://codeforces.com/: এই সাইটে নিয়মিত বিভিন্ন ধরনের প্রোগ্রামিং কনটেস্ট হয়। অভিজ্ঞ প্রোগ্রামারদের জন্য ভালো।
  9. https://www.codechef.com/: এটিও প্রোগ্রামিং প্রতিযোগিতার জন্য একটি ভালো ওয়েবসাইট এবং অভিজ্ঞ প্রোগ্রামারদের জন্য।
  10. http://acm.timus.ru/: এখানে চমৎকার কিছু প্রবলেম আছে। বেশিরভাগই রাশিয়ান কনটেস্টের।
  11. http://www.hsin.hr/coci/: এটি ক্রোয়েশিয়ান ইনফরমেটিক্স অলিম্পিয়াডের ওয়েবসাইট। এখানে মাঝে মধ্যে প্রোগ্রামিং প্রতিযোগিতা আয়োজন করা হয়ে থাকে।
  12. http://ipsc.ksp.sk/: এটি হচ্ছে IPSC (Internet Problem Solving Contest) এর ওয়েবসাইট, এখানে প্রতিবছর বিভিন্ন দেশের ওপর প্রোগ্রামিং প্রতিযোগিতা আয়োজিত হয়।
  13. কিছু চীনা অনলাইন জাজ: চীনে বেশ কিছু অনলাইন জাজ রয়েছে:
    http://acm.pku.edu.cn/icpc_pku2015/
    http://acm.zju.edu.cn/onlinejudge/
    http://acm.tju.edu.cn/toj/
    এই সাইটগুলোতে বেশ কিছু প্রোগ্রামিং সমস্যা রয়েছে। এই সাইটগুলোতে নিয়মিত প্রতিযোগিতার আয়োজন করা হয়।