Monday, November 28, 2016

Codeforces round #382, problem 735D/736B - Taxes Solution

Problem Description:

problem link

এক ব্যক্তি তার ইনকাম ট্যাক্স দিবেন । তার ইনকাম n টাকা ।
ট্যাক্স দেবার নিয়ম হলো - যদি x টাকার ট্যাক্স দেন, ট্যাক্স হবে x ছাড়া x এর সবচেয়ে বড় divisor ।
যেমন, তিনি যদি ৬ টাকার ট্যাক্স দেন, তবে তাকে ৩ টাকা ট্যাক্স দিতে হবে, যদি ২৫ টাকার ট্যাক্স দেন, তবে তাকে ৫ টাকা ট্যাক্স দিতে হবে ।
একইভাবে, x=35 হলে, Tax = 7 টাকা

লোকটি একটি বুদ্ধি বের করল, তিনি n টাকার ট্যাক্স একবারে দেবেন না, ভেঙ্গে ভেঙ্গে দেবেন । এমনভাবে দেবেন, যাতে তাকে সর্বনিম্ন Tax দিতে হয় । তবে তিনি ১ টাকার ট্যাক্স দিতে পারবেন না, যেহেতু ১ ছাড়া ১ এর আর কোন Divisor নেই ।

যেমন, তিনি ৩০ টাকার Tax দিতে চাইলে বিভিন্নভাবে দিতে পারেন-
৩০ = ২+২৮, Tax = ১+১৪ = ১৫টাকা
অথবা, ৩০ = ৩+২৭, Tax = ১+৯ = ১০ টাকা
অথবা, ৩০ = ৪+২৬, Tax = ২+১৩ = ১৫ টাকা
অথবা, ৩০ = ৫+২৫, Tax = ৫+৫ = ১০ টাকা
অথবা, ৩০ = ৬+২৪, Tax = ৩+১২ = ১৫ টাকা
অথবা, ৩০ = ৭+২৩, Tax = ১+১ = ২ টাকা
অথবা, ৩০ = ৮+১০+৭+৬, Tax = ৪+৫+১+৩ = ১৩ টাকা
...
...
...
এভাবে, আরো অনেকভাবেই তিনি ট্যাক্স দিতে পারেন ।
মানে একটি সংখ্যাকে তিনি যত ভাবে বিভিন্ন সংখ্যার যোগফল হিসেবে প্রকাশ করতে পারেন, তত উপায়ে ট্যাক্স দিতে পারেন । তার মধ্য যেভাবে ট্যাক্স দিলে, সর্বনিম্ন ট্যাক্স দিতে হবে, তিনি সেইভাবে ট্যাক্স দেবেন ।

এক্ষেত্রে, n = ৩০ এর জন্য, যেহেতু ২ সর্বনিম্ন, তাই সর্বনিম্ন ২ টাকা ট্যাক্স দিবেন ।

তোমাকে বলতে হবে, n টাকার ট্যাক্স দিতে হলে, তিনি সর্বনিম্ন কত টাকা দিতে পারবেন ?

constraint:   2<=n<=2*10^9


অ্যানালাইসিস:

খেয়াল করে দেখ, Prime Number(মৌলিক সংখ্যা) ক্ষেত্রে ঐ সংখ্যা ছাড়া সবচেয়ে বড় Divisor হলো ১ ।
তাই যদি কোন সংখ্যাকে Prime Number এর যোগফল হিসেবে ভেঙ্গে প্রতিটি Prime Number এর জন্য আলাদা ভাবে ট্যাক্স দেন, তবে প্রতিটি Prime Number এর জন্য ১ টাকা করে ট্যাক্স দিতে হবে । সংখ্যাটিকে যত গুলি Prime Number এর যোগফল হিসেবে প্রকাশ করা হবে,  মোট ট্যাক্স হবে তত ।
যেমন ৩০ এর জন্য ৩০ = ৭+২৩, এখানে ৭ ও ২৩Prime Number, তাই ট্যাক্স হবে ১+১ = ২ টাকা ।

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

তাহলে তুমি কিভাবে করবে?

তোমার মনে হতে পারে n পর্যন্ত Prime Number generate করে নিয়ে, দেখবে n কে সর্বনিম্ন কয়টি Prime Number এর যোগফল হিসেবে প্রকাশ করা যায় ।
কিন্তু এভবে করতে চাইলে, TLE খাবে ।

তাহলে এর চেয়ে সহজ উপায় কি? তুমি একটু চিন্তা করে দেখ তো ! আগে চিন্তা কর, না পারলে নিচের অংশ পড় ।

সমাধান:

কোন সংখ্যা যদি নিজেই Prime Number হয়, তবে তাকে আর ভাংতে হবে না । এক্ষেত্রে ট্যাক্স ১ টাকা ।

এখন খেয়াল কর, Goldbach's conjecture অনুযায়ী "Every even integer greater than 2 can be expressed as the sum of two primes"
তাহলে, যদি n=2 হয়, তবে যেহেতু n prime number, তাই ট্যাক্স হবে ১ টাকা । আর যদি অন্য কোন জোড় সংখ্যা হয়, তবে ট্যাক্স হবে ২ টাকা, যেহেতু বাকি সব জোড় সংখ্যাকেই দুইটি prime number এর যোগফল হিসেবে প্রকাশ করা যাবেই ।

তাহলে জোড় সংখ্যার জন্য সমাধান পেয়ে গেলাম ।

বিজোড় সংখ্যার জন্য সমাধান কি? একটু চিন্তা করে দেখ। না পারলে, নিচের অংশ দেখ ।

Goldbach's weak conjecture অনুযায়ী, "Every odd number greater than 5 can be expressed as the sum of three primes."

সমাধান তো পেয়ে গেলে !

এইটুকু পড়েই যদি সাবমিট করে থাক, তাহলে এতক্ষণে নিশ্চয় WA খেয়ে মাথা চুলকাচ্ছ !!

বিজোড় সংখ্যাকে ৩ টা প্রাইম নাম্বারের যোগফল হিসেবে প্রকাশ করা যায় ঠিকই, কিন্তু কখনো যদি দুইটি প্রাইম নাম্বারের যোগফল হিসেবে প্রকাশ করা যায়, তবে ?

যেমন, ১৫ কে ২+১৩ আকারে লেখা যায়। তাহলে ট্যাক্স হবে ২ টাকা ।

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

২ ছাড়া অন্য দুইটি প্রাইম নাম্বারের যোগফল হিসেবে কখনোই প্রকাশ করা যাবে না । কারণ দুইটি বিজোড় সংখ্যার যোগফল কখনোই বিজোড় হবে না ।

তাই একটি ২ হতে হবেই । বাকি থাকল n-2 । এখন দেখতে হবে n-2 প্রাইম কিনা । যদি হয়, তাহলে সম্ভব ।
অর্থাৎ, যদি n বিজোড় হয় এবং n-2 প্রাইম হয়, তাহলেই কেবল মাত্র একটি বিজোড় সংখ্যাকে দুইটি প্রাইম নাম্বারের যোগফল হিসেবে প্রকাশ করা যাবে ।

এই হলো প্রোবলেমটির সমাধান !!

কোড:




Sunday, May 22, 2016

LightOj 1374 / LiveArchive 6963 (Confusion in the Problemset) solution

প্রোবলেমের সংক্ষিপ্ত বর্ণনাঃ


কিছু পেজ প্রিন্ট করা হয়েছে, কিন্তু পেজ নাম্বার ভুল প্রিন্ট করা আছে ।
প্রোবলেমে বলা আছে, মোট কত গুলো পেজ আছে আর কোন পেজে পেজ নং কত প্রিন্ট করা আছে ।

আউটপুটে বলতে হবে, পেজ গুলোকে কি এমনভাবে সাজানো যাবে, যাতে করে ঐ পেজের নাম্বার পেজের আগে কত গুলো পেজ আছে তা বুঝাবে অথবা ঐ পেজের পরে কত গুলো পেজ আছে তা বুঝাবে ?

যদি এমন ভাবে সাজানো যায়, তবে "yes" প্রিন্ট করতে হবে, নতুবা "no" প্রিন্ট করতে হবে ।

সমাধানঃ


ধর, তোমার কাছে মোট ৪টা পেজ আছে ।

যেহেতু, ১ম পেজের আগে ০ টা পেজ আছে, পরে ৩ টা পেজ আছে, তাই নিয়ম অনুযায়ী এই পেজে যদি 0 বা 3 প্রিন্ট করা থাকে তবে তা সঠিক বলে ধরা হবে । তাই ১ম পেজটা এমন পেজ হতে হবে, যেই পেজে পেজ নাম্বার 0 বা 1 প্রিন্ট করা আছে ।

একইভাবে, ২য় পেজ হিসেবে রাখতে হবে এমন পেজ, যেই পেজে 1 বা 2 প্রিন্ট করা আছে । কারণ, ২য় পেজের আগে ১টি পেজ(১ম পেজ) আর পরে আরো ২ টি পেজ আছে(৩য় ও ৪র্থ পেজ)।

৩য় পেজের আগে আছে ২টি পেজ(১ম পেজ ও ২য় পেজ), আর পরে আছে ১ টি পেজ(৪র্থ পেজ) । তাই এই পেজের পেজ নাম্বার হতে হবে 2 বা 1 ।

৪র্থ পেজের আগে আছে ৩টি পেজ(১ম, ২য় ও ৩য় পেজ),  আর পরে আছে ০ টি পেজ । তাই এই পেজের পেজ নাম্বার হতে হবে 4 বা 0 ।

তাহলে, এক কথায় আমরা কি বলতে পারি ?

যদি n সংখ্যক পেজ থাকে তবে -

১ম পেজের আগে থাকবে ০ টি পেজ, পরে থাকবে n-1 সংখ্যক পেজ (প্রিন্ট করতে হবে 0 বা n-1)

২য় পেজের আগে থাকবে ১ টি পেজ, পরে থাকবে n-2 সংখ্যক পেজ  (প্রিন্ট করতে হবে 1 বা n-2)

৩য় পেজের আগে থাকবে ২ টি পেজ, পরে থাকবে n-3 সংখ্যক পেজ  (প্রিন্ট করতে হবে 2 বা n-2)
....................................................................................................................
....................................................................................................................
....................................................................................................................

i তম পেজের আগে থাকবে i-1 সংখ্যক পেজ, পরে থাকবে n-i সংখ্যক পেজ (প্রিন্ট করতে হবে i-1 বা n-i)

.......................................................................................................................
n তম পেজের আগে থাকবে n-1 সংখ্যক পেজ, পরে থাকবে n-n=0 সংখ্যক পেজ । (প্রিন্ট করতে হবে n-1 বা 0)।

অতএব, আমরা এখন জানি কোন পেজে পেজ নাম্বার কত প্রিন্ট করতে হবে ।

এখন যা জানা দরকার, তা হল, i তম পেজে পেজ নাম্বার যেহেতু 'i বা i-1' প্রিন্ট করতে হবে, আমাদের চেক করতে হবে, মোট যত গুলো পেজ আছে, তার মাঝে এমন কোন পেজ আছে কিনা যার পেজ নাম্বার 'i বা i-1' ।

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

কিন্তু প্রোবলেম এ বলা আছে, n মান হতে হতে পারে 10000 পর্যন্ত ! তাহলে প্রতি ইন্ডেক্সের মানের জন্য n সংখ্যক পেজের নাম্বার চেক করতে Time complexity হবে O(n^2) !!

আমরা কিভাবে এই Time complexity কমাতে পারি ??

আমরা যদি প্রথমেই একটা অ্যারে রাখতাম, যাতে কোন পেজ নাম্বার কত বার আছে তা থাকবে, তবে আমরা O(1) এই কিন্তু চেক করতে পারতাম, যে কাংখিত পেজ নাম্বার আছে কি নাই !!!
আর n সংখ্যক পেজের নাম্বার চেক করতে Time complexity হবে O(n) !!

আরেকটা ব্যাপার আছে, সেটা হলো - কোন পেজ নাম্বার আছে বলেই আমরা তা ইউস করতে পারব না কিন্তু !! কেন ? কেন ?? তা কেন ??? চিন্তা করে বল দেখি !

কারণ, ওই পেজ নাম্বারটা যদি আগেই ব্যবহার করে থাকি তবে তা পরে আবার কিভাবে ইউস করব ?
তবে হ্যা, আবারো ইউস করতে পারব, যদি ঐ পেজ নাম্বারটা একাধিক পেজে প্রিন্ট করা থেকে থাকে অর্থাৎ, একই পেজ নাম্বার যদি রিপিট থাকে । যেমন, ৩য় আর ৪র্থ পেজে ০ প্রিন্ট করা আছে, তাহলে আমরা এর একটা পেজ ১ম পেজ হিসেবে আরেকটা পেজ শেষ পেজ হিসেবে সাজাব !!

উদাহরণঃ
ধর, মোট পেজ আছে ৪টা আর পেজ নাম্বার গুলো এভাবে প্রিন্ট করা আছে -


এক্ষেত্রে আমাদের ans কী হবে ?

ans হবে 'yes' । 'yes' প্রিন্ট করতে হবে, কারণ আমরা পেজের নাম্বার গুলো এভাবে সাজাতে পারি -


আমরা কী করলাম ?

যেহেতু, মোট পেজ, n=4, তাই

১ম পেজে 1-1=0 বা 4-1=3 প্রিন্ট করতে হবে(কারণ, আগে আছে 0 টা পেজ, পরে আছে 3 টা পেজ), তাই ৩য় পেজটাকে এনে প্রথমে বসিয়ে দিলাম । কারণ, ৩য় পেজের পেজ নাম্বার লেখা আছে 3, (২য় পেজ বসালেও পারতাম, কারণ, ২য় পেজের নাম্বার প্রিন্ট করা আছে 0, একটা বসালেই হল )।

২য় পেজে প্রিন্ট করতে হবে 2-1=1 বা 4-2=2,(কারণ, আগে আছে ১ টা পেজ, পরে আছে ২ টা পেজ) তাই ৪র্থ পেজটাকে এনে ২য় পেজের স্থানে বসিয়ে দিলাম । কারণ, ৪র্থ পেজের পেজ নাম্বার লেখা আছে 1, (১ম পেজ বসালেও পারতাম, কারণ, ১ম পেজের নাম্বার প্রিন্ট করা আছে ২, একটা বসালেই হল )।

৩য় পেজে প্রিন্ট করতে হবে 3-1=2, বা 4-3=1, (কারণ, আগে আছে 2 টা পেজ, পরে আছে 1 টা পেজ) তাই ১ম পেজটাকে এনে ৩য় পেজের স্থানে বসিয়ে দিলাম । কারণ, ১ম পেজের পেজ নাম্বার লেখা আছে 2, (৪র্থ পেজ বসানো যেত,কারণ, ৪র্থ পেজের নাম্বার প্রিন্ট করা আছে 1, কিন্তু সেটা আগেই ২য় পেজের স্থানে বসিয়েছি)।

৪র্থ পেজে প্রিন্ট করতে হবে 4-1=3, বা 4-4=0, (কারণ, আগে আছে 3 টা পেজ, পরে আছে 0 টা পেজ) তাই ২য় পেজটাকে এনে ৪র্থ পেজের স্থানে বসিয়ে দিলাম । কারণ, ২য় পেজের পেজ নাম্বার লেখা আছে 0, (৩য় পেজ বসানো যেত,কারণ, ৩য় পেজের নাম্বার প্রিন্ট করা আছে 3, কিন্তু সেটা আগেই ১ম পেজের স্থানে বসিয়েছি)।

সব তো বলে ফেললাম, এবার তোমার কাজ হল, নিজে কোড টা লিখে ফেলা ! তাহলে ঝটপট কোড লিখে ফেল, আর অনলাইন জাজে সাবমিট করে ফেল !!

প্রোবলেম লিঙ্কঃ
LightOj 1374
ACM-ICPC Live Archive 5963

যদি কোড লিখতে সমস্যা হয় তার জন্য নিচে কোড দিয়ে দিলাম । তবে নিজে আগে চেস্টা না করে কোড দেখবে না । একান্তই না পারলে তখন হেল্প নিতে পার ।

Source Code:



বিঃদ্রঃ গত ১৯-০৫-২০১৬ তারিখে শ্রদ্বেয় Azad Abul Kalam স্যার আমাদের জন্য একটি কন্টেস্টের আয়োজন করেছিলেন, যেই কন্টেস্টের সাথে একই সময়ে, আমার একটি ইনকোর্স পরীক্ষার সময়ও পরে যায় । আমি কন্টেস্টে অংশ নেবার লোভ সামলাতে না পেরে - ইনকোর্স পরীক্ষা না দিয়ে কন্টেস্টে অংশ নেই :)

কন্টেস্টে মোট ছয়টি প্রোবলেমের মধ্যে সব চেয়ে মজার প্রোবলেম ছিল এটি, যেটি সলভ করে এত মজা পেয়েছিলাম যে, বলে বুঝাতে পারব না !! :) ইনকোর্সে ৫ এ ৫ পেলেও যে মজার কোটি ভাগের এক ভাগও পেতাম না । ফলে, ইনকোর্স পরীক্ষা না দিয়ে প্রোগ্রামিং কন্টেস্টে অংশ নেয়া সার্থক হয়েছিল, এই প্রোবলেমটি সলভ করতে পারায় :)
কন্টেস্টে ১ম, ২য় ও ৩য় স্থান অধিকারীর জন্য ছিল স্যারের পক্ষ থেকে আকর্ষণীয় পুরস্কার (টি-শার্ট, কলম ইত্যাদি)।
কন্টেস্টে এই প্রোবলেমটি শুধু আমিই সলভ করতে পেরেছিলাম, আর এজন্যই কন্টেস্টে আমার চ্যাম্পিয়ন হওয়াটাও সম্ভব হয়েছিল :) ইনকোর্স পরীক্ষা না দিয়ে প্রোগ্রামিং কন্টেস্টে অংশ নেয়াও সার্থক হয়েছিল :)
অতএব, প্রোবলেমটির বিশেষ মাহাত্ব্য রয়েছে :)