Dan u nedelji
Danas je dan sa rednim brojem d (0 = ponedeljak, …, 6 = nedelja). Koji će dan biti posle k dana? k može biti i negativno (pre koliko dana), |k| ≤ 1018. Ispiši redni broj dana.
Primer 1
Ulaz
0 10Izlaz
3Primer 2
Ulaz
2 -9Izlaz
0Pregled tema iz teorije brojeva koje se najčešće javljaju na okružnom, državnom i SIO nivou: deljivost, prosti brojevi, NZD, modularna aritmetika i brzo stepenovanje. Za svaku temu postoji kratak podsetnik i link na detaljnu lekciju; modularna aritmetika je ovde objašnjena u celosti.
Broj a je deljiv sa b ako je a % b == 0. Ostatak pri deljenju je osnova mnogih zadataka: cifre broja (% 10), parnost (% 2), ciklusi (dan u nedelji je % 7). Pazi: u C++-u je ostatak negativnog broja negativan (-7 % 3 == -1), pa se za matematički ostatak piše ((a % m) + m) % m.
√n – Prosti brojevi i faktorizacija.O(n log log n).n = p₁^a₁ · … · pₖ^aₖ, broj delilaca je (a₁+1)·…·(aₖ+1).Euklidov algoritam: nzd(a, b) = nzd(b, a % b), složenost O(log min(a, b)). NZS je a / nzd(a, b) * b. U C++17 postoje gotove funkcije gcd i lcm (zaglavlje <numeric>). Detaljno: Određivanje NZD i NZS.
Kada je tačan rezultat ogroman (broj puteva, broj rasporeda…), zadatak traži ostatak pri deljenju nekim brojem m, najčešće 109 + 7 (prost broj). Važe pravila:
(a + b) mod m = ((a mod m) + (b mod m)) mod m(a − b) mod m = ((a mod m) − (b mod m) + m) mod m(a · b) mod m = ((a mod m) · (b mod m)) mod mZato se ostatak uzima posle svake operacije, pa međurezultati ostaju mali. Proizvod dva broja manja od 109+7 je manji od 1018 i staje u long long.
Deljenje ne radi po istom pravilu. Umesto deljenja sa a množi se modularnim inverzom a⁻¹ – brojem za koji je a · a⁻¹ mod m = 1. Kada je m prost i a nije deljiv sa m, po maloj Fermaovoj teoremi a⁻¹ = am−2 mod m.
#include <iostream>
using namespace std;
const long long MOD = 1000000007;
long long stepen(long long a, long long b) { // a^b mod MOD
long long r = 1;
a %= MOD;
while (b > 0) {
if (b & 1) r = r * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return r;
}
long long inverz(long long a) { return stepen(a, MOD - 2); }
int main() {
long long a, b;
cin >> a >> b;
cout << (a + b) % MOD << "\n";
cout << ((a - b) % MOD + MOD) % MOD << "\n"; // nikad negativno
cout << a % MOD * (b % MOD) % MOD << "\n";
cout << a % MOD * inverz(b) % MOD << "\n"; // "a / b" po modulu
return 0;
}
Poslednji red za a = 10, b = 4 daje 500000006 – to je broj x za koji je 4 · x ≡ 10 (mod 109+7), tj. „10/4 = 2,5“ po modulu.
ab mod m za b do 1018 računa se u O(log b) koraka, polovljenjem izložioca (funkcija stepen iznad). Objašnjenje korak po korak: Algoritam brzog stepenovanja, a rekurzivna verzija u lekciji Faktorijel, stepen i NZD – rekurzivno.
Za svaki zadatak postoji primer, uputstvo i rešenje. Rešenja su provereno tačna na primerima iz teksta.
Danas je dan sa rednim brojem d (0 = ponedeljak, …, 6 = nedelja). Koji će dan biti posle k dana? k može biti i negativno (pre koliko dana), |k| ≤ 1018. Ispiši redni broj dana.
0 1032 -90Učitaj prirodan broj n (n ≤ 1012) i ispiši koliko ima delilaca.
1261000000000000169Izračunaj 1/1 + 1/2 + … + 1/n po modulu 109+7 (n ≤ 106), tj. ispiši Σ i⁻¹ mod p.
113833333341long long prekorači opseg.((x % m) + m) % m.p * p <= n (bez sqrt i grešaka zaokruživanja).1. Koliko je -7 % 3 u C++-u?
2. Koliko delilaca ima broj 36 = 2² · 3²?
3. Kada je inverz a⁻¹ = a^(m−2) mod m tačan?