Formule umesto petlji: zbirovi i brojanje

Lekcija 3 od 4 · Složenost algoritama

Mnoge petlje u zadacima samo sabiraju ili broje. Za takve petlje često postoji gotova formula koja daje rezultat odmah, i za brojeve veće od milijardu. Ova lekcija sakuplja najkorisnije formule, sa programima i proverom na primerima.

Pre nego što počneš: potrebno predznanje – zamena iteracija formulom, kombinatorika.
Kako da učiš: svaki primer prekucaj i pokreni, a zadatke na kraju prvo reši sam/a; uputstvo i rešenje otvori tek posle toga. Svi programi su u C++-u.

Najvažniji zbirovi

ZbirFormulaPrimer
1 + 2 + … + nn(n + 1) / 2n = 100 → 5050
1² + 2² + … + n²n(n + 1)(2n + 1) / 6n = 3 → 14
1³ + 2³ + … + n³(n(n + 1) / 2)²n = 3 → 36
a + (a+d) + … (n članova)n · (2a + (n − 1)d) / 2aritmetički niz
1 + q + q² + … + qn−1(qⁿ − 1) / (q − 1)q = 2: 2ⁿ − 1
a + (a+1) + … + b(a + b)(b − a + 1) / 23 + … + 7 = 25
Redosled operacija: u formuli n * (n + 1) / 2 prvo se množi pa deli – proizvod je uvek paran pa je deljenje tačno. Za n do 109 proizvod je do 1018, pa mora long long. Za n do 2·109 i više – podeli parni činilac pre množenja.

Koliko brojeva je deljivo sa k?

Od 1 do n ima tačno n / k (celobrojno deljenje) brojeva deljivih sa k. U intervalu [a, b] ih ima b / k − (a − 1) / k (za pozitivne a i b). Njihov zbir je k · (1 + 2 + … + m) = k · m(m + 1) / 2, gde je m = n / k.

Za brojeve deljive sa 3 ili 5 koristi se uključenje–isključenje: deljivi sa 3 + deljivi sa 5 − deljivi sa 15 (oni su ubrojani dva puta).

#include <iostream>
using namespace std;

// zbir svih brojeva od 1 do n deljivih sa k
long long zbirDeljivih(long long n, long long k) {
    long long m = n / k;                 // toliko ih ima: k, 2k, ..., mk
    return k * (m * (m + 1) / 2);
}

int main() {
    long long n;
    cin >> n;
    // deljivi sa 3 ili 5 = sa 3 + sa 5 - sa 15
    cout << zbirDeljivih(n, 3) + zbirDeljivih(n, 5) - zbirDeljivih(n, 15) << endl;
    return 0;
}

Za n = 10: 3 + 5 + 6 + 9 + 10 = 33. Petlja do 109 bi trajala sekundu, a formula je trenutna i radi i za 1012 (uz pažnju na prekoračenje).

Brojanje parova i rasporeda

PitanjeFormulaZašto
koliko rukovanja ima n ljudi (svako sa svakim)n(n − 1) / 2parovi bez redosleda
koliko uređenih parova različitih elemenatan(n − 1)prvi pa drugi
koliko podnizova (uzastopnih delova) ima niz dužine nn(n + 1) / 2biraju se početak i kraj
koliko kvadrata (svih veličina) ima tabla n × n1² + 2² + … + n²kvadrata veličine k ima (n − k + 1)²
koliko pravougaonika ima tabla n × mC(n+1, 2) · C(m+1, 2)biraju se dve horizontalne i dve vertikalne linije
koliko podskupova ima skup od n elemenata2ⁿsvaki element je unutra ili nije

Više o ovome je u lekciji Kombinatorika.

Brojanje po grupama

Česta ideja: umesto da se broje parovi direktno, prebroje se elementi po grupama, pa se za svaku grupu primeni formula. Primer: koliko ima parova pozicija i < j sa a[i] = a[j]? Ako se vrednost v javlja c puta, ona daje c(c − 1)/2 parova:

#include <iostream>
#include <map>
using namespace std;

int main() {
    int n;
    cin >> n;
    map<long long, long long> br;            // koliko puta se javlja svaka vrednost
    for (int i = 0; i < n; i++) {
        long long x;
        cin >> x;
        br[x]++;
    }
    long long parova = 0;
    for (auto &p : br) parova += p.second * (p.second - 1) / 2;
    cout << parova << endl;
    return 0;
}

Umesto O(n²) poređenja svih parova – O(n log n). Ovo je ista ideja kao u zadatku sa binarnim stringom u lekciji Zamena iteracija formulom.

Zadaci za vežbu

Za svaki zadatak postoji primer, uputstvo i rešenje. Rešenja su provereno tačna na primerima iz teksta.

ZADATAK 01Težina: Srednje

Kvadrati na tabli

Koliko ima kvadrata svih veličina na tabli n × n (1 ≤ n ≤ 106)? Na šahovskoj tabli (n = 8) ih ima 204.

Primer 1

Ulaz

1

Izlaz

1

Primer 2

Ulaz

2

Izlaz

5

Primer 3

Ulaz

8

Izlaz

204

Primer 4

Ulaz

1000000

Izlaz

333333833333500000
ZADATAK 02Težina: Lako

Deljivi u intervalu

Dati su brojevi a, b i k (1 ≤ a ≤ b ≤ 1018, 1 ≤ k ≤ 1018). Koliko brojeva iz [a, b] je deljivo sa k?

Primer 1

Ulaz

1 10 3

Izlaz

3

Primer 2

Ulaz

10 20 5

Izlaz

3

Primer 3

Ulaz

7 7 2

Izlaz

0
ZADATAK 03Težina: Lako

Rukovanja na turniru

Na turniru igra n ekipa (n ≤ 109) i svaka igra sa svakom po dva puta (domaćin i gost). Koliko ima utakmica?

Primer 1

Ulaz

4

Izlaz

12

Primer 2

Ulaz

1000000000

Izlaz

999999999000000000
Česte greške i saveti
  • Pre deljenja proveri da je proizvod deljiv (n(n + 1) je uvek paran).
  • Za n do 109 i više koristi long long u svim međurezultatima.
  • Formulu proveri na malom primeru (n = 1, 2, 3) – i uporedi sa petljom.

Proveri znanje

Otvori kviz

Formule umesto petlji

1. Koliko je 1 + 2 + … + 200?




2. Koliko brojeva od 1 do 100 je deljivo sa 7?




3. Koliko uzastopnih delova ima niz od 5 elemenata?