Dixtosa Episode II - Analysis...
Eშისაიდან მოვიდა 3**13?ისე 4 * 52 * 3**13 = 331M+ ...
|
Quick GeOlymp 2013 - ფინალური ეპიზოდი იწყება...
Upsolving ჩაირთო...
|
saba_tavdgiridze GeOlymp 2013 - ფინალური ეპიზოდი იწყება...
აღარ მინდა.:)...
|
saba_tavdgiridze GeOlymp 2013 - ფინალური ეპიზოდი იწყება...
B ამოცანის 17 ტესტს ვერ მიმანიშნებთ?...
|
tornike5 GeOlymp 2013 - ფინალის შესახებ...
ვაპირებდი იგივე მეკითხა მარა მეგონა უეჭველი იქნება...
|
giorgi123 GeOlymp 2013 - ფინალის შესახებ...
მადლობა.შარშან ფინალში ამოცანების ყურებით ვიფარგლე...
|
Elle GeOlymp 2013 - ფინალის შესახებ...
შარშან ფინალს codeblocks-ით წერდით?დავაყენეთ codeb...
|
ვისაც აინტერესებს, ეს რისი ბრალია, უნდა იცოდეთ რისი მეშვეობით ახერხებს vector ამორტიზებულ O(1) დროში (მარტივად რომ ვთქვათ, "სწრაფად") ელემენტის დამატებას. და რომ გესმოდეთ, რატომ არაა ეგ მარტივი, უნდა იცოდეთ როგორ ხდება მეხსიერებაში მასივის შენახვა.
თვითონ მასივის განმარტებით, იგი გახლავთ ერთნაირი ტიპის ელემენტების ერთობლიობა, რომელიც მეხსიერებაში მიმდევრობითაა განლაგებული. წარმოიდგინეთ, რომ თქვენ შექმენით მასივი X და შემოიღეთ სხვა ცვლადებიც/მასივებიც. თქვენ ვერ აკონტროლებთ, სად ჩაწერს ოპერაციული სისტემა თქვენს მიერ აღწერილ ცვლადებს და მასივებს, ამიტომ შეიძლება X მასივისგან უშუალოდ მარჯვნივ რამე სხვა ობიექტი ჩაიწეროს. X-ში ელემენტის დამატება რომ მოინდომოთ, ან მთელი მასივი, ან ის მარჯვნვი ჩაწერილი ობიექტი სხვა ადგილას გახდება გადასატანი, რასაც ოპერაციული სისტემა არ აკეთებს. ამიტომ მასივი რა ზომისაც შევქმენით თავიდან, იმ ზომის რჩება ბოლომდე.
მაშინ როგორ მუშაობს vector? იგი ელემენტებს მასივით ინახავს სწრაფი წვდომისთვის, მაგრამ გარკვეულ შემთხვევებში ამ მასივს შლის და ქმნის ახალს, რომლის სიგრძე ორჯერ მეტია წინაზე. მაგალითად, თუ vector-ის მასივის სიგრძე 2-ის ტოლია და მასში მხოლოდ 1 ელემენტია მიმდინარე მომენტში, მაშინ ელემენტის ჩამატებისას იგი თავისუფალ ადგილს დაიკავებს. აი კიდევ ერთი ელემენტის ჩამატებას რომ მოვინდომებთ, vector ავტომატურად შექმნის 4-ელემენტიან მასივს, გადაიტანს მასში თავის ძველ 2 ელემენტს, დაუმატებს ახალს და ძველ 2-ელემენტიან მასივს გაანადგურებს. როდესაც vector-ში ელემენტების რაოდენობა 4-ს მიაღწევს, იგი ანალოგიური გზით 8 სიგრძის მასივს შექმნის და ძველს წაშლის. ერთი შეხედვით, ეს არც ისე სწრაფია, მაგრამ დააკვირდით, რომ თუ vector-ში ჩავამატეთ N ელემენტი, მისი სიგრძე აუცილებლად 2N-ზე ნაკლებია, ხოლო ოპერაციების რაოდენობა, რომელიც ჯამში შესრულდა N ელემენტის დასამატებლად, ასევე 2N-ის პროპორციულია (1+2+4+...+2^i ხომ (2^(i+1)-1)-ის ტოლია).
ამრიგად, როგორც GeOlymp-ის ამოცანებში, ასევე სხვა შეჯიბრებზე vector-ების მასივებად გადაკეთება მნიშვნელოვნად არ ასწრაფებს ამოხსნას, თუ ვექტორის კარგად გამოყენება იცით.
inline-ს რაც შეეხება, არც ერთ შეჯიბრზე არ მქონია შემთხვევა, რომ მის გარეშე ამოხსნა ნელი ყოფილიყო და მას იგი გადაერჩინა. იგივე ეხება register იდენტიფიკატორს, რომელიც ცვლადებს ეწერებათ და მათ რეგისტრებში (ყველაზე სწრაფად წვდომად მეხსიერებაში) უნდა ათავსებდეს.
მეხსიერებაზე წვდომას უკავშირდება ერთი მნიშვნელოვანი მომენტი, რომელიც ბევრმა შეიძლება არ იცოდეს. თქვენი მასივები კი ინახება ოპერატიულ მეხსიერებაში, მაგრამ როდესაც რომელიმე მასივის რომელიმე ელემენტზე წვდომას ახორციელებთ, ოპერაციულ სისტემას ამ მასივის გარკვეული ფრაგმენტი (მეხსიერების ის ფურცელი, სადაც ეს ელემენტი ინახება - ფურცლის ზომა კი მგონი 64 კილობაიტია) მოაქვს უფრო სწრაფად წვდომად მეხსიერებაში - ქეშში (cache). ქეშში შენახული ფრაგმენტის წაკითხვა ბევრად უფრო სწრაფად ხდება და ამიტომ თუ თქვენ შემდეგ მიწვდებით ამ ელემენტის მეზობელ ელემენტს, ეს ოპერაცია უცებ მოხდება (და არა მარტო მეზობელს, 64 კილობაიტში ხომ რამდენიმე ათასი ელემენტი ჩაეტევა). ხოლო თუ მასივის ელემენტებზე წვდომას არეული მიმდევრობით დაიწყებთ და მასივი იმდენად დიდია, რომ რამდენიმე ფურცელს იკავებს, შეიძლება ბევრად მეტი დრო დაიხარჯოს. ქეშის ზომები განსხვავდება, მაგრამ საშუალოდ 1-2 მეგაბაიტია ხოლმე (ისე ანდრო, რამდენია ჩვენს სერვერზე?), ამიტომ იგი ვერ შეინახავს ყველა იმ ფურცელს, რომელზეც წვდომას მოახდენთ და ზოგჯერ მას ძველი ფურცლების "დავიწყება" მოუწევს. და ხშირად თუ მოუწევს ახალ-ახალი ფურცლების ჩატვირთვა, ცუდად იქნება საქმე.
ამოხსნის დაწერისას აუცილებლად უნდა ითვალისწინებდეთ ოპერაციების "სიმძიმეს". მაგალითად, შეკრება და გამოკლება იაფი ოპერაციებია და სერვერზე შეიძლება 500-600 მილიონი შეკრება ერთ წამში ხორციელდებოდეს. შედარებით უფრო მძიმეა გამრავლების ოპერაცია. ყველაზე ცუდადაა საქმე გაყოფასთან და ნაშთის აღებასთან. ეს ოპერაციები 40-50 მილიონი ესწრება 1 წამში. მაგალითად, თუ თქვენს პროგრამას რამდენიმე მილიონჯერ სჭირდება p1/q1 და p2/q2 წილადების შედარება, აზრი აქვს რომ ამის ნაცვლად მოახდინოთ p1*q2 და p2*q1 სიდიდეების შედარება (ამას არა მხოლოდ სწრაფქმედებისთვის აქვს აზრი, მაგრამ ეს უკვე სხვა საკითხია).
ნიკას ნათქვამზეც გავაკეთებ კომენტარს. რა თქმა უნდა, თუ ალგორითმი ოპტიმალურია, კარგია რომ მისი ნებისმიერი რეალიზაცია გამოყოფილ დროში ეტეოდეს. ზოგიერთ ამოცანაში არაოპტიმალური ალგორითმები 1000-ჯერ უფრო ნელია ოპტიმალურზე და ეს მარტივად მიიღწევა. მაგრამ მთელ რიგ შემთხვევებში განსხვავება ასეთი რადიკალური არ გამოდის, ამიტომ მონაწილემ თვითონ უნდა შეაფასოს, რამდენად მძიმე ოპერაციების ჩატარება შეუძლია საკმარისად სწრაფ ამოხსნაში. მაგალითად, წლევანდელი პირველი ეპიზოდის ამოცანა C-ში გრაფის მეზობელთა სიებით შენახვა და sqrt ფუნქციის გამოყენება ერთად დიდი ალბათობით ამოხსნას ჩააგდებდა, მაგრამ თუ შეზღუდვებს დავწევთ ისე, რომ ნებისმიერად დაწერილი კვადრატული ამოხსნა 1 წამში ეტეოდეს, შეიძლება 1 წამში ჩაეტიოს კუბური სირთულის სხვა ამოხსნებიც.
ამ თემის ადგილი კი არც GeOlymp-ის შეჯიბრებებშია და არც ზოგად პროგრამირებაში. ერთის მხვრივ, საუბარი შეჯიბრებზე ვარგის და უვარგის ოპტიმიზაციებზეა და ზოგად პროგრამირებასთან მისი კავშირი ნაკლებია. მეორეს მხვრივ, GeOlymp-ზე არაა რაიმე სპეციალური გარემო, რომელსაც განსაკუთრებული ხერხები და ოპტიმიზაციები სჭირდება. აქ იგივე კანონები მუშაობს, რაც სხვა შეჯიბრებზე. ამრიგად, თემა "სწავლა/დახმარება" ქვეფორუმში გადადის.