Python

Input/Output

Nie je hádam nič horšie než striedať input() a print(). Každý input() flushne print() a všetko bufferovanie ide do kanála. Ak máme úlohu s veľa sadami (napríklad milíon), oplatí sa nám výsledky uložiť do poľa a vypísať až na koniec.

Podobne, aj v úlohách kde máme veľa riadkov vstupu (a nie nutne veľa riadkov výstupu) sa nám môže oplatiť nevolať milíon krát input. Radšej si načítame celý vstup naraz a potom už si riadkovanie robíme sami.

import sys
lines = sys.stdin.read().split("\n")

Vstavané funkcie

Oheň vie byť sluha i pán. Tak isto vstavané funkcie nám vedia pomôcť i uškodiť. Ak chceme zistiť maximum poľa, nenájdeme lepší prístup než funkciu max(). Ak chceme zistiť maximum dvoch prvkov, nenájdeme horší prístup než funkciu max().

V programovaní sa často snažíme nájsť najlepší výsledok, či už pri hľadaní najkratšej cesty alebo dynamike. Často sa teda v kóde vyskytne výraz best = max(best, aktual). Python je v takomto prípade hlupáčik a tento jeden riadok je v niektorých dynamikách najpomalšia časť celého kódu. Nahradíme ho vlastným if aktual > best: best = aktual a získame niekedy 2x rýchlejší kód.

Snažme sa používať čo najviac vstavaných funkcií, pretože nám uľahčujú život a skrášlujú kód, až na prípady kedy nie.

Ďalej upozornime, že existujú vstavané funkcie a štruktúry bisect.bisect_left, collections.Counter, collections.deque a heapq. Neodporúčame používať modul queue.

Globálny skôp

Zober svoj kód. Daj ho do def solve():. Zavolaj solve(). Python je znova hlúpučký a global kód vie byť triviálne 3x pomalší než ten istý kód s týmito dvoma riadkami navyše.

https://stackoverflow.com/questions/11241523/why-does-python-code-run-faster-in-a-function

PyPy

Väčšina týchto optimalizácii je zbytočná ak jednoducho použijeme PyPy. :/

Najväčí trik

Čo je najväčší trik? Optimalizovať keď treba. Urob si odhad časovej zložitosti. Zakomentuj časti kódu. Zamysli sa nad worst case prípadom. Ak netreba optimalizovať, tak netreba!

Úloha na grafe, program TLEie. Možno pomôže ak sem dám if podmienka: break. Problém je, že táto podmienka sa nikdy nespustí na grafe tvaru cesta a na ňom to tiež dáva TLE. Tento if je potom iba zbytočný kód, v ktorom môže byť chyba, ktorý musím potom už navždy zvažovať či mi kód vlastne nespomaluje, či mi nespôsobí WA, ...

Počul som že max() je pomalé tak všade používam if. Ten max by sa ale počas behu programu zavolal sto krát a iná časť kódu, ktorú si neoptimalizoval/a sa vykoná sto milíonov krát. Gratulujem, máš neprehľadný rozvetvený kód ktorý nie je o nič rýchlejší.

Venujte svoju pozornosť tam kam treba a keď treba. A často aj keď si myslíte, že treba, tak netreba a problém je celkom iný než by sa zdalo.

C++

Rýchle IO

Stačí cin.tie(0)->sync_with_stdio(0);. Nič viac. cout.tie(0) je zbytočné.

Vstavané funkcie

Používajte begin(x), end(x), size(x) namiesto x.begin(), ... Funguje to aj na C polia.

Užitočné funkcie ktoré už dúfam poznáte: all_of, find, count, swap, fill, unique, reverse, sort, lower_bound, max_element, next_permutation. Povinne pozrieť https://en.cppreference.com/w/cpp/algorithm (ale lepšie je to vidno na https://cplusplus.com/reference/algorithm/)

Príklad použitia:

sort(begin(pole), end(pole));
pole.resize(unique(begin(pole), end(pole)) - begin(pole));

alebo

set<int> set_pole(begin(pole), end(pole));
vector<int> unique_pole(begin(set_pole), end(set_pole));
auto maxi = *max_element(begin(pole), end(pole));

Vypisovanie štruktúr

Stačia dva operator<< overaloady na vypisovanie všetkého:

// vypisovanie ľubovolného iterovateľného kontajnéru
// bez kolízie voči string a const char* vďaka basic_ostream<A, B> namiesto ostream
template <typename A, typename B, typename C>
basic_ostream<A, B>& operator<<(basic_ostream<A, B>& os, const C& cont) {
    for (auto it = begin(cont); it != end(cont); ++it)
        os << (it == begin(cont) ? "" : " ") << *it;
    return os;
}

// plus vypisovanie pairov a mame aj associatívne kontajnery
template<typename T1, typename T2>
ostream& operator<<(ostream& os, const pair<T1, T2>& p) {
    return os << '(' << p.first << ", " << p.second << ')';
}

https://codeforces.com/blog/entry/68920

Polia

Skúšali ste niekedy robiť dynamiku? Otrava že. Ale menej ak použijeme C-čkové polia. Ach jaj C++...

int D[100][100][100] = {0};
// ak chceme niečo iné ako 0, pozor, memset nefunguje lebo to robí po bajtoch
fill((int*)begin(a), (int*)end(a), 1e9);

C++ má svoj std::array<T, N>. Celkom nifty štruktúra, lepšie array<int, 3> než tuple<int, int, int>. Nájdite si miesta kde vám to pomôže.

Čas poslednej úpravy: 16. november 2023 17:24