Asosiy mazmunga o'tish

37-dars: Optimallashtirish

5-darajaOlimpiada — musobaqa mahorati33–40 darslar

Bu darsdan keyin siz

  • kirish-chiqishni tez o’qiydigan shablonni yodda saqlaysiz
  • bir xil murakkablikdagi yechimlarni konstanta bo’yicha solishtirasiz
  • Python chegarasini bilib, qachon C++ kerakligini ayta olasiz

Avval qo‘lda

~6 daqiqajuftlikdaKompyuter va sekundomer

Bitta masalani uch xil yozing: 1 dan n gacha yig’indi. Birinchisi oddiy sikl, ikkinchisi sum(range(n + 1)), uchinchisi n * (n + 1) // 2.

n = 10⁶ da uchalasini yurgizib vaqtini yozing. Nisbatlar qanday chiqdi?

Nimani sezishingiz kerak

Uchalasi ham to’g’ri javob berdi. Birinchi va ikkinchi yechimning murakkabligi bir xil — O(n) — lekin vaqt o’nlab barobar farq qildi. Uchinchisi esa umuman aylanmadi.

Kompyuter yopiq. Bu mashq tugamaguncha kod ochilmaydi.

Olimpiadadagi har Python yechimi shu ikki qatordan boshlanadi. Ular hiyla emas — ular standart.

tez kirish-chiqish
import sysmalumot = sys.stdin.buffer.read().split()n = int(malumot[0])a = [int(x) for x in malumot[1 : 1 + n]]sys.stdout.write(str(sum(a)) + "\n")
konstantaconstant factor

Murakkablik bahosida ko’rinmaydigan ko’paytuvchi. O(n) ikki yechimning biri ikkinchisidan 50 barobar sekin bo’lishi mumkin.

Avval o'ylang: bu kod nima chiqaradi? Ishga tushirishdan oldin yozing.

Bashorat qiling
n = 1000jami = 0for x in range(1, n + 1):  jami += xprint(jami, sum(range(1, n + 1)), n * (n + 1) // 2)
Javobni ko'rish
500500 500500 500500

Uchta yechim, bir xil javob. Birinchisi n marta Python amali bajaradi, ikkinchisi bittasini (qolgani C tilida), uchinchisi esa hech qanday sikl ishlatmaydi.

Amaliy qoidalar qisqa. Python siklidan qutulish mumkin bo’lsa — qutuling: sum, max, min, ro’yxat tushunchalari va join hammasi C tilida bajariladi. Ro’yxatga append qilish += bilan satr yig’ishdan ancha tez. Va dict yoki set ga har murojaat narxi bor — uni siklning ichida takrorlamang.

Sig‘adimi?

Bir soniyada taxminan 10⁸ oddiy amal bajariladi.

Yechimn = 100 000n = 10⁶n = 10⁷
C++ (taxminan)n100 000sig‘adi10⁶sig‘adi10⁷sig‘adi
Python (taxminan 10–50 barobar sekin)n log n10⁶sig‘adi10⁷sig‘adi10⁸chegarada

Yashil — yechim o‘tadi. Sariq — chegarada, konstanta va til muhim bo‘lib qoladi. Qizil — bu yechim bilan bormaydi, boshqasini qidiring.

Jadval qo’pol, lekin nisbat to’g’ri. Amalda bu shunday ko’rinadi: n ≤ 10⁵ bo’lgan masalalarning deyarli hammasi Python’da o’tadi, n = 10⁶ da ehtiyot bo’lish kerak, n = 10⁷ da esa optimal algoritm ham yetmasligi mumkin.

Xuddi shu yechim ikki tilda quyidagicha ko’rinadi.

yigindi.py
import sysmalumot = sys.stdin.buffer.read().split()n = int(malumot[0])a = [int(x) for x in malumot[1 : 1 + n]]print(sum(a), max(a))
yigindi.cpp
#include <bits/stdc++.h>using namespace std;int main() {  ios::sync_with_stdio(false);  cin.tie(nullptr);  int n;  cin >> n;  long long jami = 0;  int eng = 0;  for (int i = 0; i < n; i++) {      int x;      cin >> x;      jami += x;      eng = max(eng, x);  }  cout << jami << " " << eng << endl;}

Diqqat qiling: jami uchun long long olingan. int bilan yozilsa million ta milliardgacha son qo’shilganda jimgina buziladiC++ sahifasidagi eng birinchi ogohlantirish shu haqda edi.

Vaqt haqida ko’p gapiriladi, xotira haqida kam — lekin u ham nol ball beradi. Python’da ro’yxatdagi har butun son taxminan 28 bayt joy oladi, ya’ni 10⁷ sonli ro’yxat yuzlab megabaytga chiqadi.

Yechim oddiy: kerak bo’lmasa ro’yxat yasamang. Generator ishlating (sum(int(x) for x in ...)), yoki array moduli bilan ishlang.

Vizualda uch yechimning Python darajasidagi amal soni yonma-yon turadi. Farq murakkablikda emas, konstantada.

Konstanta — bir xil murakkablik, boshqa narx

Har qator bitta yechimning Python darajasidagi amal soni.

Bir xil murakkablikdagi yechimlar konstanta tufayli o'nlab barobar farq qilishi mumkin.

Algoritmning har qadami quyidagi ro‘yxatda matn sifatida ham berilgan — vizual faqat shu qadamlarni chizadi, yangi ma’lumot qo‘shmaydi.

  1. Bir masala: 1 dan n gacha yig'indi. Uch yechim ham TO'G'RI. Qatorlarda har biri nechta PYTHON amali bajarishi ko'rsatiladi.
  2. n = 10^4. Python sikli 10000 marta aylanadi. sum(range(n)) esa bitta chaqiruv: qo'shishlar C tilida bajariladi, ya'ni taxminan o'n barobar arzon. Formula umuman aylanmaydi.
  3. n = 10^5. Python sikli 100000 marta aylanadi. sum(range(n)) esa bitta chaqiruv: qo'shishlar C tilida bajariladi, ya'ni taxminan o'n barobar arzon. Formula umuman aylanmaydi.
  4. n = 10^6. Python sikli 1000000 marta aylanadi. sum(range(n)) esa bitta chaqiruv: qo'shishlar C tilida bajariladi, ya'ni taxminan o'n barobar arzon. Formula umuman aylanmaydi.
  5. Uchalasining murakkabligi bir xil emas: sikl va sum() — O(n), formula — O(1). Lekin muhimi boshqa: BIR XIL murakkablikdagi ikki yechim ham o'nlab barobar farq qilishi mumkin. Konstanta olimpiadada ball keltiradi.
n
10^4010^5110^62
sikl
sum()
formula

Bir masala: 1 dan n gacha yig'indi. Uch yechim ham TO'G'RI. Qatorlarda har biri nechta PYTHON amali bajarishi ko'rsatiladi.

Jami Python amali0

1/5

Tuzoq — xatoni toping

37 / 40

MasalaYechimim O(n log n), chegara 10⁵. Vaqt chegarasidan oshdi. Nima qilaman?

Taklif qilingan mulohaza

Bu javobning 2-qismi noto'g'ri. Xulosa shoshilinch. Avval KONSTANTANI tekshirish kerak: kirish input() bilan o'qilganmi, chiqish har qatorda alohida print bilan berilganmi, sikl ichida keraksiz ro'yxat yasalmayaptimi. Ko'p holatda shu uchtasini tuzatish yetadi va tilni almashtirish kerak bo'lmaydi.

Javobning qaysi qismi noto'g'ri? Bosib belgilang.

1input() nega sekin?

Javobni ko'rish

Har chaqiruvda satr obyekti yasaladi, dekodlanadi va tozalanadi. Million marta chaqirilganda bu ish bir necha soniya oladi.

2Bir xil murakkablikdagi ikki yechim qancha farq qilishi mumkin?

Javobni ko'rish

O’nlab barobar. Murakkablik o’sish tezligini beradi, narxni emas — konstanta bahoda ko’rinmaydi.

3Vaqt chegarasidan oshganda birinchi navbatda nima tekshiriladi?

Javobni ko'rish

Kirish-chiqish. Keyin sikl ichidagi keraksiz ish. Til almashtirish — oxirgi chora.

4C++ da yig'indi uchun nega long long olinadi?

Javobni ko'rish

int taxminan 2·10⁹ gacha son saqlaydi. Undan oshsa xato bermay jimgina buziladi.

5Python'da xotira chegarasi qachon muammo bo'ladi?

Javobni ko'rish

10⁷ va undan katta ro’yxatlarda: har butun son taxminan 28 bayt oladi. Yechim — ro’yxat o’rniga generator yoki array moduli.

Masalalar

3 ta

  • Weird AlgorithmCSES 1068oson

    Javob juda uzun bo‘ladi. Har sonni alohida print qilmang — ro‘yxatga yig‘ib, join bilan chiqaring.

  • Distinct NumbersCSES 1621oson

    Ikki yechimni ham yozing (to‘plam va saralash) va vaqtini solishtiring — farq sezilarli.

  • Sum of Three ValuesCSES 1641qiyin

    n ≤ 5000, yechim n². Python‘da bu chegarada konstanta hal qiluvchi bo‘ladi.

Lokal mashq: mashqlar/37-kirish/ — masala matni, testlar va tekshir.py. Avval sekin.py ni o‘zingiz yozing, keyin tayyorini oching.

Topshiriq — darajangizni tanlang

Asos · 5–7-sinf — Vizual va aniq ko'rsatmali

1 dan 10⁶ gacha yig’indini uch usulda yozing va vaqtini o’lchang. Uch raqamni jadvalga yozing va nisbatlarni hisoblang.

Mustahkam · 8–9-sinf — Matnli masala, o'zingiz tuzasiz

37-kirish masalasini yeching. sekin.py va tez.py vaqtini 20 000 sonli testda solishtiring, keyin natijani n = 10⁶ uchun bashorat qiling.

Chuqur · 10–11-sinf — Algoritmik, chegara holatlari bilan

O’zingizning shaxsiy chegara jadvalingizni tuzing: bo’sh sikl, qo’shish bilan sikl, ro’yxatga append, dict ga yozish va set da qidirish — har biri uchun 10⁶ amalda qancha vaqt ketadi? Bu jadval keyingi har masalada qaror qabul qilishga yordam beradi.

Darsni belgilash uchun JavaScript kerak. Bu progressni saqlash uchun ishlatiladi — darslikning o'zi JavaScript'siz ham to'liq o'qiladi.