ProFIIT 2018 Vysvetlenia riešení problémov Peter Trebatický et al. 7.4.2018 Peter Trebatický et al. ProFIIT 2018 7.4.2018 1 / 41
1 Poradie Peter Trebatický 2 Heslá Michal Maňak 3 3 3 Peter Kmec 4 Logy Kamil Janeček 5 Binárna hra Veronika Žatková 6 Zaujímavé čísla - Márius Šajgalík Peter Trebatický et al. ProFIIT 2018 7.4.2018 2 / 41
Ako priebežného víťaza si označíme virtuálneho súťažiaceho s 0 vyriešenými príkladmi. Peter Trebatický et al. ProFIIT 2018 7.4.2018 3 / 41
Ako priebežného víťaza si označíme virtuálneho súťažiaceho s 0 vyriešenými príkladmi. Pri načítaní priebehu súťaže si pre každého súťažiaceho priebežne zaznačujeme koľko príkladov zatiaľ vyriešil. Peter Trebatický et al. ProFIIT 2018 7.4.2018 3 / 41
Ako priebežného víťaza si označíme virtuálneho súťažiaceho s 0 vyriešenými príkladmi. Pri načítaní priebehu súťaže si pre každého súťažiaceho priebežne zaznačujeme koľko príkladov zatiaľ vyriešil. Ak po pripočítaní vyriešeného príkladu má súťažiaci najviac vyriešených príkladov, zapamätáme si ho ako priebežného víťaza. Peter Trebatický et al. ProFIIT 2018 7.4.2018 3 / 41
Ako priebežného víťaza si označíme virtuálneho súťažiaceho s 0 vyriešenými príkladmi. Pri načítaní priebehu súťaže si pre každého súťažiaceho priebežne zaznačujeme koľko príkladov zatiaľ vyriešil. Ak po pripočítaní vyriešeného príkladu má súťažiaci najviac vyriešených príkladov, zapamätáme si ho ako priebežného víťaza. Ako vyriešiť, keď majú viacerí rovnaký počet príkladov? Peter Trebatický et al. ProFIIT 2018 7.4.2018 3 / 41
Ako priebežného víťaza si označíme virtuálneho súťažiaceho s 0 vyriešenými príkladmi. Pri načítaní priebehu súťaže si pre každého súťažiaceho priebežne zaznačujeme koľko príkladov zatiaľ vyriešil. Ak po pripočítaní vyriešeného príkladu má súťažiaci najviac vyriešených príkladov, zapamätáme si ho ako priebežného víťaza. Ako vyriešiť, keď majú viacerí rovnaký počet príkladov? Priebežného víťaza zmeníme len vtedy, ak má ostro viac príkladov, t.j. nie keď má rovnako ako doterajšie maximum. Peter Trebatický et al. ProFIIT 2018 7.4.2018 3 / 41
Ako priebežného víťaza si označíme virtuálneho súťažiaceho s 0 vyriešenými príkladmi. Pri načítaní priebehu súťaže si pre každého súťažiaceho priebežne zaznačujeme koľko príkladov zatiaľ vyriešil. Ak po pripočítaní vyriešeného príkladu má súťažiaci najviac vyriešených príkladov, zapamätáme si ho ako priebežného víťaza. Ako vyriešiť, keď majú viacerí rovnaký počet príkladov? Priebežného víťaza zmeníme len vtedy, ak má ostro viac príkladov, t.j. nie keď má rovnako ako doterajšie maximum. Na konci za celkového víťaza prehlásime priebežného víťaza. Peter Trebatický et al. ProFIIT 2018 7.4.2018 3 / 41
Vzorové riešenie Const MAX = 10000; Var T, s, i, j, N, best: longint; cnt: array [0..MAX] of integer; Begin cnt[0] := 0; readln(t); for s := 1 to T do begin for i := 1 to MAX do cnt[i] := 0; best := 0; read(n); for j := 1 to N do begin read(i); inc(cnt[i]); if cnt[i] > cnt[best] then best := i; end; writeln(best); end; End. Peter Trebatický et al. ProFIIT 2018 7.4.2018 4 / 41
1 Poradie Peter Trebatický 2 Heslá Michal Maňak 3 3 3 Peter Kmec 4 Logy Kamil Janeček 5 Binárna hra Veronika Žatková 6 Zaujímavé čísla - Márius Šajgalík Peter Trebatický et al. ProFIIT 2018 7.4.2018 5 / 41
Rozdané heslá môžu byť maximálne 50 znakové. Peter Trebatický et al. ProFIIT 2018 7.4.2018 6 / 41
Rozdané heslá môžu byť maximálne 50 znakové. Možné riešenie je vyskúšať všetky možnosti, odstrániť duplikáty a spočítať, koľko zostalo rôznych hesiel. Peter Trebatický et al. ProFIIT 2018 7.4.2018 6 / 41
Rozdané heslá môžu byť maximálne 50 znakové. Možné riešenie je vyskúšať všetky možnosti, odstrániť duplikáty a spočítať, koľko zostalo rôznych hesiel. Kedy dostaneme rovnaké heslá? Peter Trebatický et al. ProFIIT 2018 7.4.2018 6 / 41
Rozdané heslá môžu byť maximálne 50 znakové. Možné riešenie je vyskúšať všetky možnosti, odstrániť duplikáty a spočítať, koľko zostalo rôznych hesiel. Kedy dostaneme rovnaké heslá?...xy... Peter Trebatický et al. ProFIIT 2018 7.4.2018 6 / 41
Rozdané heslá môžu byť maximálne 50 znakové. Možné riešenie je vyskúšať všetky možnosti, odstrániť duplikáty a spočítať, koľko zostalo rôznych hesiel. Kedy dostaneme rovnaké heslá?...xy......y... (po vymazaní X) Peter Trebatický et al. ProFIIT 2018 7.4.2018 6 / 41
Rozdané heslá môžu byť maximálne 50 znakové. Možné riešenie je vyskúšať všetky možnosti, odstrániť duplikáty a spočítať, koľko zostalo rôznych hesiel. Kedy dostaneme rovnaké heslá?...xy......y... (po vymazaní X)...X... (po vymazaní Y) Peter Trebatický et al. ProFIIT 2018 7.4.2018 6 / 41
Rozdané heslá môžu byť maximálne 50 znakové. Možné riešenie je vyskúšať všetky možnosti, odstrániť duplikáty a spočítať, koľko zostalo rôznych hesiel. Kedy dostaneme rovnaké heslá?...xy......y... (po vymazaní X)...X... (po vymazaní Y) Rovnaké heslá dostaneme, keď X = Y. Peter Trebatický et al. ProFIIT 2018 7.4.2018 6 / 41
Rozdané heslá môžu byť maximálne 50 znakové. Možné riešenie je vyskúšať všetky možnosti, odstrániť duplikáty a spočítať, koľko zostalo rôznych hesiel. Kedy dostaneme rovnaké heslá?...xy......y... (po vymazaní X)...X... (po vymazaní Y) Rovnaké heslá dostaneme, keď X = Y. Stačí spočítať počet rôznych susedov a pripočítať 1. Peter Trebatický et al. ProFIIT 2018 7.4.2018 6 / 41
Vzorové riešenie Var T, i, pocet: integer; heslo: AnsiString; Begin readln(t); for T := T downto 1 do begin readln(heslo); pocet := 1; for i := 2 to length(heslo) do begin if heslo[i] <> heslo[i - 1] then pocet := pocet + 1; end; writeln(pocet); end; End. Peter Trebatický et al. ProFIIT 2018 7.4.2018 7 / 41
1 Poradie Peter Trebatický 2 Heslá Michal Maňak 3 3 3 Peter Kmec 4 Logy Kamil Janeček 5 Binárna hra Veronika Žatková 6 Zaujímavé čísla - Márius Šajgalík Peter Trebatický et al. ProFIIT 2018 7.4.2018 8 / 41
Peter Trebatický et al. ProFIIT 2018 7.4.2018 9 / 41
Riešením príkladu je prehľadávanie do šírky. (BFS, https://en.wikipedia.org/wiki/breadth-first_search). Nebudeme hľadať riešenie pre každé zadanie ale vypočítame všetky riešenia z cieľovej pozície. Každú pozíciu navštívime práve raz, kedy si zapamätáme level, v ktorom sme navštívili túto pozíciu prvý krát. Následne vypíšene pre každú úlohu predpočítaný minimálny počet krokov. Komponenty riešenia: Reprezentácia pozície 3 3. Peter Trebatický et al. ProFIIT 2018 7.4.2018 10 / 41
Riešením príkladu je prehľadávanie do šírky. (BFS, https://en.wikipedia.org/wiki/breadth-first_search). Nebudeme hľadať riešenie pre každé zadanie ale vypočítame všetky riešenia z cieľovej pozície. Každú pozíciu navštívime práve raz, kedy si zapamätáme level, v ktorom sme navštívili túto pozíciu prvý krát. Následne vypíšene pre každú úlohu predpočítaný minimálny počet krokov. Komponenty riešenia: Reprezentácia pozície 3 3. Queue (FIFO) Peter Trebatický et al. ProFIIT 2018 7.4.2018 10 / 41
Riešením príkladu je prehľadávanie do šírky. (BFS, https://en.wikipedia.org/wiki/breadth-first_search). Nebudeme hľadať riešenie pre každé zadanie ale vypočítame všetky riešenia z cieľovej pozície. Každú pozíciu navštívime práve raz, kedy si zapamätáme level, v ktorom sme navštívili túto pozíciu prvý krát. Následne vypíšene pre každú úlohu predpočítaný minimálny počet krokov. Komponenty riešenia: Reprezentácia pozície 3 3. Queue (FIFO) Hash tabuľku, pre jednotlivé pozície Peter Trebatický et al. ProFIIT 2018 7.4.2018 10 / 41
Riešením príkladu je prehľadávanie do šírky. (BFS, https://en.wikipedia.org/wiki/breadth-first_search). Nebudeme hľadať riešenie pre každé zadanie ale vypočítame všetky riešenia z cieľovej pozície. Každú pozíciu navštívime práve raz, kedy si zapamätáme level, v ktorom sme navštívili túto pozíciu prvý krát. Následne vypíšene pre každú úlohu predpočítaný minimálny počet krokov. Komponenty riešenia: Reprezentácia pozície 3 3. Queue (FIFO) Hash tabuľku, pre jednotlivé pozície Funkciu na posun políčok Peter Trebatický et al. ProFIIT 2018 7.4.2018 10 / 41
Reprezentácia pozície 3 3 Postačuje nám dlhé číslo 876543210, ktoré bude reprezentovať rozloženie. Peter Trebatický et al. ProFIIT 2018 7.4.2018 11 / 41
Queue (FIFO) Keďže celkový počet možností rozloženia je len 9! Teda počet možností je len 9! ako queue použijeme pole kde si budeme pamätať aktuálnu hodnotu a veľkosť queue. Peter Trebatický et al. ProFIIT 2018 7.4.2018 12 / 41
Hash tabuľu, pre jednotlivé pozície Ak by sme chceli použiť pole ako hash tabuľku potrebovali by sme alokovať veľa miesta. Každé rozloženie je permutácie čísla 876543210 bez opakovania. Môžeme použiť ako hash funkciu poradové číslo permutácie. 876543210 = 362879 876543201 = 362878... 12345687 = 1 12345678 = 0 Peter Trebatický et al. ProFIIT 2018 7.4.2018 13 / 41
Funkciu na posun políčok Súradnice v X,Y x = index mod 3 y = index div 3 Súradnice v poli i-index s ošetrením hrany. Left i - 1, i mod 3!= 2 Top i - 3, i div 3!= 2 Right i + 1, i mod 3!= 0 Bottom i + 3, i div 3!= 0 Peter Trebatický et al. ProFIIT 2018 7.4.2018 14 / 41
1 Poradie Peter Trebatický 2 Heslá Michal Maňak 3 3 3 Peter Kmec 4 Logy Kamil Janeček 5 Binárna hra Veronika Žatková 6 Zaujímavé čísla - Márius Šajgalík Peter Trebatický et al. ProFIIT 2018 7.4.2018 15 / 41
Zadanie Máme reťazec zložený z malých písmen anglickej abecedy, napr. abcd. Peter Trebatický et al. ProFIIT 2018 7.4.2018 16 / 41
Zadanie Máme reťazec zložený z malých písmen anglickej abecedy, napr. abcd. Tento reťazec sa K krát zopakuje, teda dostaneme napr. abcdabcd. Peter Trebatický et al. ProFIIT 2018 7.4.2018 16 / 41
Zadanie Máme reťazec zložený z malých písmen anglickej abecedy, napr. abcd. Tento reťazec sa K krát zopakuje, teda dostaneme napr. abcdabcd. Našou úlohou je zistiť, koľko krát je v tomto výslednom reťazci dvojica a a b tak, že a sa vyskytuje v reťazci skôr ako b. Peter Trebatický et al. ProFIIT 2018 7.4.2018 16 / 41
Zadanie Máme reťazec zložený z malých písmen anglickej abecedy, napr. abcd. Tento reťazec sa K krát zopakuje, teda dostaneme napr. abcdabcd. Našou úlohou je zistiť, koľko krát je v tomto výslednom reťazci dvojica a a b tak, že a sa vyskytuje v reťazci skôr ako b. Teda v prípade reťazca abcdabcd je počet takýchto dvojíc rovný 3. Peter Trebatický et al. ProFIIT 2018 7.4.2018 16 / 41
Problém sa skladá z 2 častí Najprv je nutné zistiť počet dvojíc v pôvodnom reťazci. Peter Trebatický et al. ProFIIT 2018 7.4.2018 17 / 41
Problém sa skladá z 2 častí Najprv je nutné zistiť počet dvojíc v pôvodnom reťazci. Následne je potrebné zistiť koľko dvojíc nám pribudlo tvorbou nového reťazca. Peter Trebatický et al. ProFIIT 2018 7.4.2018 17 / 41
Zistenie počtu dvojíc v pôvodnom reťazci Tento počet je možné získať jedným prechodom cez celý reťazec. Peter Trebatický et al. ProFIIT 2018 7.4.2018 18 / 41
Zistenie počtu dvojíc v pôvodnom reťazci Tento počet je možné získať jedným prechodom cez celý reťazec. Počas iterácie si ukladáme počty a-čiek a b-čiek. Pričom ak narazíme na b, tak k celkovému výsledku pripočítame počet a, na ktoré sme zatiaľ narazili. Peter Trebatický et al. ProFIIT 2018 7.4.2018 18 / 41
Zistenie počtu dvojíc v pôvodnom reťazci Tento počet je možné získať jedným prechodom cez celý reťazec. Počas iterácie si ukladáme počty a-čiek a b-čiek. Pričom ak narazíme na b, tak k celkovému výsledku pripočítame počet a, na ktoré sme zatiaľ narazili. for (std::string::iterator it = str.begin(); it!= str.end(); ++it) { if (*it == a ) { a++; } else if (*it == b ) { b++; ab += a; } } Peter Trebatický et al. ProFIIT 2018 7.4.2018 18 / 41
Zistenie počtu dvojíc, ktoré pribudli po vytvorení reťazca Ako sa zmení počet dvojíc ak za pôvodný reťazec prilepíme daľší rovnaký? abc abcabc Peter Trebatický et al. ProFIIT 2018 7.4.2018 19 / 41
Zistenie počtu dvojíc, ktoré pribudli po vytvorení reťazca Ako sa zmení počet dvojíc ak za pôvodný reťazec prilepíme daľší rovnaký? abc abcabc Pribudne nám: Peter Trebatický et al. ProFIIT 2018 7.4.2018 19 / 41
Zistenie počtu dvojíc, ktoré pribudli po vytvorení reťazca Ako sa zmení počet dvojíc ak za pôvodný reťazec prilepíme daľší rovnaký? abc abcabc Pribudne nám: Toľko dvojíc ako bolo v pôvodnom reťazci. Peter Trebatický et al. ProFIIT 2018 7.4.2018 19 / 41
Zistenie počtu dvojíc, ktoré pribudli po vytvorení reťazca Ako sa zmení počet dvojíc ak za pôvodný reťazec prilepíme daľší rovnaký? abc abcabc Pribudne nám: Toľko dvojíc ako bolo v pôvodnom reťazci. Pre každé a, ktoré predcháza prilepenému reťazcu, môžeme pripočíťať k výsledku toľko, koľko je v pôvodnom reťazci písmen b. Peter Trebatický et al. ProFIIT 2018 7.4.2018 19 / 41
Zistenie počtu dvojíc, ktoré pribudli po vytvorení reťazca Ako sa zmení počet dvojíc ak za pôvodný reťazec prilepíme daľší rovnaký? abc abcabc Pribudne nám: Toľko dvojíc ako bolo v pôvodnom reťazci. Pre každé a, ktoré predcháza prilepenému reťazcu, môžeme pripočíťať k výsledku toľko, koľko je v pôvodnom reťazci písmen b. Tento postup opakujeme pri každom zväčšovaní reťazca. Peter Trebatický et al. ProFIIT 2018 7.4.2018 19 / 41
Zistenie počtu dvojíc, ktoré pribudli po vytvorení reťazca Ako sa zmení počet dvojíc ak za pôvodný reťazec prilepíme daľší rovnaký? abc abcabc Pribudne nám: Toľko dvojíc ako bolo v pôvodnom reťazci. Pre každé a, ktoré predcháza prilepenému reťazcu, môžeme pripočíťať k výsledku toľko, koľko je v pôvodnom reťazci písmen b. Tento postup opakujeme pri každom zväčšovaní reťazca. Keď tieto pozorovania spojíme, získame výsledný vzorec. Peter Trebatický et al. ProFIIT 2018 7.4.2018 19 / 41
Zistenie počtu dvojíc, ktoré pribudli po vytvorení reťazca Ako sa zmení počet dvojíc ak za pôvodný reťazec prilepíme daľší rovnaký? abc abcabc Pribudne nám: Toľko dvojíc ako bolo v pôvodnom reťazci. Pre každé a, ktoré predcháza prilepenému reťazcu, môžeme pripočíťať k výsledku toľko, koľko je v pôvodnom reťazci písmen b. Tento postup opakujeme pri každom zväčšovaní reťazca. Keď tieto pozorovania spojíme, získame výsledný vzorec. res = K pocet ab + pocet b K 1 i=1 (i pocet a) Kde K je počet opakovaní reťazca pocet a je počet a v pôvodnom reťazci. pocet b je počet b v pôvodnom reťazci. pocetab je počet dvojíc ab v pôvodnom reťazci. Peter Trebatický et al. ProFIIT 2018 7.4.2018 19 / 41
Hotovo Už stačí iba aplikovať vzorec pre aritmetickú postupnosť ( n ( a 1 +a n )) 2 a získame finálny vzorec Peter Trebatický et al. ProFIIT 2018 7.4.2018 20 / 41
Hotovo Už stačí iba aplikovať vzorec pre aritmetickú postupnosť ( n ( a 1 +a n )) 2 a získame finálny vzorec res = K pocet ab + pocet b K 1 i=1 (i pocet a) Peter Trebatický et al. ProFIIT 2018 7.4.2018 20 / 41
Hotovo Už stačí iba aplikovať vzorec pre aritmetickú postupnosť ( n ( a 1 +a n )) 2 a získame finálny vzorec res = K pocet ab + pocet b K 1 i=1 (i pocet a) res = K * ab; res += a * b * ( (K - 1) * (1 + (K - 1))/2 ); Peter Trebatický et al. ProFIIT 2018 7.4.2018 20 / 41
Hotovo Už stačí iba aplikovať vzorec pre aritmetickú postupnosť ( n ( a 1 +a n )) 2 a získame finálny vzorec res = K pocet ab + pocet b K 1 i=1 (i pocet a) res = K * ab; res += a * b * ( (K - 1) * (1 + (K - 1))/2 ); Pozor na pretečenie. Peter Trebatický et al. ProFIIT 2018 7.4.2018 20 / 41
1 Poradie Peter Trebatický 2 Heslá Michal Maňak 3 3 3 Peter Kmec 4 Logy Kamil Janeček 5 Binárna hra Veronika Žatková 6 Zaujímavé čísla - Márius Šajgalík Peter Trebatický et al. ProFIIT 2018 7.4.2018 21 / 41
Dvaja hráči hrajú hru: Na vstupe sa objaví náhodné celé kladné číslo. Hráč na ťahu si spočíta počet jednotiek v jeho binárnom zápise a odpočíta od neho menšie číslo s práve jednou jednotkou v binárnom zápise. Peter Trebatický et al. ProFIIT 2018 7.4.2018 22 / 41
Dvaja hráči hrajú hru: Na vstupe sa objaví náhodné celé kladné číslo. Hráč na ťahu si spočíta počet jednotiek v jeho binárnom zápise a odpočíta od neho menšie číslo s práve jednou jednotkou v binárnom zápise. Hráč si opäť spočíta počet jednotiek v binárnom zápise nového čísla. Ak sa počty jednotiek v binárnych zápisoch pôvodného aj nového čísla zhodujú, hráč neprehral a na ťahu je súper, ktorý pokračuje s výsledným číslom. Ak sa nezhodujú, resp. hráč nevedel potiahnuť, vyhráva súper a hra končí. Peter Trebatický et al. ProFIIT 2018 7.4.2018 22 / 41
Dvaja hráči hrajú hru: Na vstupe sa objaví náhodné celé kladné číslo. Hráč na ťahu si spočíta počet jednotiek v jeho binárnom zápise a odpočíta od neho menšie číslo s práve jednou jednotkou v binárnom zápise. Hráč si opäť spočíta počet jednotiek v binárnom zápise nového čísla. Ak sa počty jednotiek v binárnych zápisoch pôvodného aj nového čísla zhodujú, hráč neprehral a na ťahu je súper, ktorý pokračuje s výsledným číslom. Ak sa nezhodujú, resp. hráč nevedel potiahnuť, vyhráva súper a hra končí. Hráči hrajú vždy optimálne. Peter Trebatický et al. ProFIIT 2018 7.4.2018 22 / 41
Príklad: N = 11 Peter Trebatický et al. ProFIIT 2018 7.4.2018 23 / 41
Príklad: N = 11 11: 1011 Peter Trebatický et al. ProFIIT 2018 7.4.2018 23 / 41
Príklad: N = 11 11: 1011 Hráč 1 odpočíta 4 (100) Peter Trebatický et al. ProFIIT 2018 7.4.2018 23 / 41
Príklad: N = 11 11: 1011 Hráč 1 odpočíta 4 (100) Nové číslo: 7 Peter Trebatický et al. ProFIIT 2018 7.4.2018 23 / 41
Príklad: N = 11 11: 1011 Hráč 1 odpočíta 4 (100) Nové číslo: 7 7: 111 Peter Trebatický et al. ProFIIT 2018 7.4.2018 23 / 41
Príklad: N = 11 11: 1011 Hráč 1 odpočíta 4 (100) Nové číslo: 7 7: 111 Počty jednotiek sa zhodujú, na ťahu je hráč 2 Peter Trebatický et al. ProFIIT 2018 7.4.2018 23 / 41
Príklad: N = 11 11: 1011 Hráč 1 odpočíta 4 (100) Nové číslo: 7 7: 111 Počty jednotiek sa zhodujú, na ťahu je hráč 2 N = 7 (111) Peter Trebatický et al. ProFIIT 2018 7.4.2018 23 / 41
Príklad: N = 11 11: 1011 Hráč 1 odpočíta 4 (100) Nové číslo: 7 7: 111 Počty jednotiek sa zhodujú, na ťahu je hráč 2 N = 7 (111) Neexistuje číslo s práve jednou jednotkou v binárnom zápise také, ktoré by hráč 2 mohol odčítať od 7 a výsledok by mal rovnaký počet nastavených bitov ako 7 Peter Trebatický et al. ProFIIT 2018 7.4.2018 23 / 41
Príklad: N = 11 11: 1011 Hráč 1 odpočíta 4 (100) Nové číslo: 7 7: 111 Počty jednotiek sa zhodujú, na ťahu je hráč 2 N = 7 (111) Neexistuje číslo s práve jednou jednotkou v binárnom zápise také, ktoré by hráč 2 mohol odčítať od 7 a výsledok by mal rovnaký počet nastavených bitov ako 7 Hráč 2 prehráva, hráč 1 je víťaz Peter Trebatický et al. ProFIIT 2018 7.4.2018 23 / 41
Ako zistiť, kto vyhrá, v rozumnom čase a pre N 1 000 000? Peter Trebatický et al. ProFIIT 2018 7.4.2018 24 / 41
Ako zistiť, kto vyhrá, v rozumnom čase a pre N 1 000 000? Každé číslo (stav hry) má iba 1 víťaza Peter Trebatický et al. ProFIIT 2018 7.4.2018 24 / 41
Ako zistiť, kto vyhrá, v rozumnom čase a pre N 1 000 000? Každé číslo (stav hry) má iba 1 víťaza Stav je pre aktuálneho hráča výherný, ak z neho dokáže potiahnuť tak, aby súpera dostal do stavu, ktorý bude pre neho určite prehrávajúci (hráči hrajú optimálne, nepotiahnú tak, aby súpera dostal do výherného stavu) Peter Trebatický et al. ProFIIT 2018 7.4.2018 24 / 41
Ako zistiť, kto vyhrá, v rozumnom čase a pre N 1 000 000? Každé číslo (stav hry) má iba 1 víťaza Stav je pre aktuálneho hráča výherný, ak z neho dokáže potiahnuť tak, aby súpera dostal do stavu, ktorý bude pre neho určite prehrávajúci (hráči hrajú optimálne, nepotiahnú tak, aby súpera dostal do výherného stavu) Pre každé číslo si stanovíme, či je pre hráča vyhrávajúce Peter Trebatický et al. ProFIIT 2018 7.4.2018 24 / 41
Ako zistiť, kto vyhrá, v rozumnom čase a pre N 1 000 000? Každé číslo (stav hry) má iba 1 víťaza Stav je pre aktuálneho hráča výherný, ak z neho dokáže potiahnuť tak, aby súpera dostal do stavu, ktorý bude pre neho určite prehrávajúci (hráči hrajú optimálne, nepotiahnú tak, aby súpera dostal do výherného stavu) Pre každé číslo si stanovíme, či je pre hráča vyhrávajúce Ako to reprezentovať? Peter Trebatický et al. ProFIIT 2018 7.4.2018 24 / 41
Ako zistiť, kto vyhrá, v rozumnom čase a pre N 1 000 000? Každé číslo (stav hry) má iba 1 víťaza Stav je pre aktuálneho hráča výherný, ak z neho dokáže potiahnuť tak, aby súpera dostal do stavu, ktorý bude pre neho určite prehrávajúci (hráči hrajú optimálne, nepotiahnú tak, aby súpera dostal do výherného stavu) Pre každé číslo si stanovíme, či je pre hráča vyhrávajúce Ako to reprezentovať? číslo 0 1 2 3 4 5 víťaz 2 2 1 2 2 1 Peter Trebatický et al. ProFIIT 2018 7.4.2018 24 / 41
Ako zistiť, kto vyhrá, v rozumnom čase a pre N 1 000 000? Každé číslo (stav hry) má iba 1 víťaza Stav je pre aktuálneho hráča výherný, ak z neho dokáže potiahnuť tak, aby súpera dostal do stavu, ktorý bude pre neho určite prehrávajúci (hráči hrajú optimálne, nepotiahnú tak, aby súpera dostal do výherného stavu) Pre každé číslo si stanovíme, či je pre hráča vyhrávajúce Ako to reprezentovať? číslo 0 1 2 3 4 5 víťaz 2 2 1 2 2 1 Ako toto pole vypočítam? Peter Trebatický et al. ProFIIT 2018 7.4.2018 24 / 41
Poznám výhernosť stavov 0 a 1 - prehrám v nich Peter Trebatický et al. ProFIIT 2018 7.4.2018 25 / 41
Poznám výhernosť stavov 0 a 1 - prehrám v nich Odpočítať môžem vždy len mocninu 2 Peter Trebatický et al. ProFIIT 2018 7.4.2018 25 / 41
Poznám výhernosť stavov 0 a 1 - prehrám v nich Odpočítať môžem vždy len mocninu 2 2: hráč 1 môže odpočítať iba číslo 1 Peter Trebatický et al. ProFIIT 2018 7.4.2018 25 / 41
Poznám výhernosť stavov 0 a 1 - prehrám v nich Odpočítať môžem vždy len mocninu 2 2: hráč 1 môže odpočítať iba číslo 1 číslo 0 1 2 3 4 5 víťaz 2 2 1 Peter Trebatický et al. ProFIIT 2018 7.4.2018 25 / 41
Poznám výhernosť stavov 0 a 1 - prehrám v nich Odpočítať môžem vždy len mocninu 2 2: hráč 1 môže odpočítať iba číslo 1 číslo 0 1 2 3 4 5 víťaz 2 2 1 3: Neviem nič odpočítať (prehrávam) Peter Trebatický et al. ProFIIT 2018 7.4.2018 25 / 41
Poznám výhernosť stavov 0 a 1 - prehrám v nich Odpočítať môžem vždy len mocninu 2 2: hráč 1 môže odpočítať iba číslo 1 číslo 0 1 2 3 4 5 víťaz 2 2 1 3: Neviem nič odpočítať (prehrávam) číslo 0 1 2 3 4 5 víťaz 2 2 1 2 Peter Trebatický et al. ProFIIT 2018 7.4.2018 25 / 41
Poznám výhernosť stavov 0 a 1 - prehrám v nich Odpočítať môžem vždy len mocninu 2 2: hráč 1 môže odpočítať iba číslo 1 číslo 0 1 2 3 4 5 víťaz 2 2 1 3: Neviem nič odpočítať (prehrávam) číslo 0 1 2 3 4 5 víťaz 2 2 1 2 4: Môžem odpočítať iba 2 a prehrávam Peter Trebatický et al. ProFIIT 2018 7.4.2018 25 / 41
Poznám výhernosť stavov 0 a 1 - prehrám v nich Odpočítať môžem vždy len mocninu 2 2: hráč 1 môže odpočítať iba číslo 1 číslo 0 1 2 3 4 5 víťaz 2 2 1 3: Neviem nič odpočítať (prehrávam) číslo 0 1 2 3 4 5 víťaz 2 2 1 2 4: Môžem odpočítať iba 2 a prehrávam číslo 0 1 2 3 4 5 víťaz 2 2 1 2 2 Peter Trebatický et al. ProFIIT 2018 7.4.2018 25 / 41
Poznám výhernosť stavov 0 a 1 - prehrám v nich Odpočítať môžem vždy len mocninu 2 2: hráč 1 môže odpočítať iba číslo 1 číslo 0 1 2 3 4 5 víťaz 2 2 1 3: Neviem nič odpočítať (prehrávam) číslo 0 1 2 3 4 5 víťaz 2 2 1 2 4: Môžem odpočítať iba 2 a prehrávam číslo 0 1 2 3 4 5 víťaz 2 2 1 2 2 5: Ak odpočítam 2, súper prehrá Peter Trebatický et al. ProFIIT 2018 7.4.2018 25 / 41
Poznám výhernosť stavov 0 a 1 - prehrám v nich Odpočítať môžem vždy len mocninu 2 2: hráč 1 môže odpočítať iba číslo 1 číslo 0 1 2 3 4 5 víťaz 2 2 1 3: Neviem nič odpočítať (prehrávam) číslo 0 1 2 3 4 5 víťaz 2 2 1 2 4: Môžem odpočítať iba 2 a prehrávam číslo 0 1 2 3 4 5 víťaz 2 2 1 2 2 5: Ak odpočítam 2, súper prehrá číslo 0 1 2 3 4 5 víťaz 2 2 1 2 2 1 Peter Trebatický et al. ProFIIT 2018 7.4.2018 25 / 41
Určenie vyhrávajúcich a prehrávajúcich čísiel Procedure precompute(size: longint); Begin End; Peter Trebatický et al. ProFIIT 2018 7.4.2018 26 / 41
Určenie vyhrávajúcich a prehrávajúcich čísiel Procedure precompute(size: longint); Begin Predpočítam si pole mocnín 2 po N count_powers(size) End; Peter Trebatický et al. ProFIIT 2018 7.4.2018 27 / 41
Predpočítanie mocnín 2 Procedure count_powers(size: longint); Begin foo := ceil(log2(size)); for i := 0 to (foo - 1) do begin pows[i] := round(power(2, i)); end; End; Peter Trebatický et al. ProFIIT 2018 7.4.2018 28 / 41
Určenie vyhrávajúcich a prehrávajúcich čísiel Procedure precompute(size: longint); Begin count_powers(size) Predpočítam si počet 1 v binárnych zápisoch čísiel po N count_set_bits(size); End; Peter Trebatický et al. ProFIIT 2018 7.4.2018 29 / 41
Predpočítanie počtov jednotiek v binárnych zápisoch čisiel Procedure count_set_bits(size: longint); Begin for i := 0 to (size - 1) do begin foo := i; ct := 0; while foo > 0 do begin ct += foo and 1; foo := foo shr 1; end; ones[i] := ct; end; End; Peter Trebatický et al. ProFIIT 2018 7.4.2018 30 / 41
Určenie vyhrávajúcich a prehrávajúcich čísiel Procedure precompute(size: longint); Begin count_powers(size) count_set_bits(size); iniciujem všetky stavy na prehrávajúce for i := 0 to (size - 1) do game[i] := false; pre každý stav určím, či z neho viem vyhrať for i := 2 to (size - 1) do begin tu budem skúšať odčítať všetky menšie mocniny 2 a zistím, či viem súpera dostať do prehrávajúceho stavu end; End; Peter Trebatický et al. ProFIIT 2018 7.4.2018 31 / 41
Určenie vyhrávajúcich a prehrávajúcich čísiel Procedure precompute(size: longint); Begin for i := 0 to (size - 1) do game[i] := false; for i := 2 to (size - 1) do begin foo := ceil(log2(i)); for j := 0 to (foo - 1) do begin num := i - pows[j]; // skusam novy stav if (ones[i] = ones[num]) and (not game[num]) then begin game[i] := true; break; end; end; end; Peter Trebatický et al. ProFIIT 2018 7.4.2018 32 / 41
Zhrnutie Hráč 1 vyhrá, ak dokáže potiahnuť tak, aby súpera dostal do stavu, v ktorom určite prehrá Peter Trebatický et al. ProFIIT 2018 7.4.2018 33 / 41
Zhrnutie Hráč 1 vyhrá, ak dokáže potiahnuť tak, aby súpera dostal do stavu, v ktorom určite prehrá Vyskúšame všetky možné ťahy, akonáhle existuje taký, ktorý dostane súpera do prehrávajúceho stavu, hráč 1 ho urobí (hrá optimálne), preto v aktuálnom stave vyhrá Peter Trebatický et al. ProFIIT 2018 7.4.2018 33 / 41
Zhrnutie Hráč 1 vyhrá, ak dokáže potiahnuť tak, aby súpera dostal do stavu, v ktorom určite prehrá Vyskúšame všetky možné ťahy, akonáhle existuje taký, ktorý dostane súpera do prehrávajúceho stavu, hráč 1 ho urobí (hrá optimálne), preto v aktuálnom stave vyhrá Ak taký ťah neexistuje, prehrá. Peter Trebatický et al. ProFIIT 2018 7.4.2018 33 / 41
Zhrnutie Hráč 1 vyhrá, ak dokáže potiahnuť tak, aby súpera dostal do stavu, v ktorom určite prehrá Vyskúšame všetky možné ťahy, akonáhle existuje taký, ktorý dostane súpera do prehrávajúceho stavu, hráč 1 ho urobí (hrá optimálne), preto v aktuálnom stave vyhrá Ak taký ťah neexistuje, prehrá. Pre výpočet výhernosti nového ťahu sme využívali už predtým vypočítané výsledky - memoizácia Peter Trebatický et al. ProFIIT 2018 7.4.2018 33 / 41
Zhrnutie Hráč 1 vyhrá, ak dokáže potiahnuť tak, aby súpera dostal do stavu, v ktorom určite prehrá Vyskúšame všetky možné ťahy, akonáhle existuje taký, ktorý dostane súpera do prehrávajúceho stavu, hráč 1 ho urobí (hrá optimálne), preto v aktuálnom stave vyhrá Ak taký ťah neexistuje, prehrá. Pre výpočet výhernosti nového ťahu sme využívali už predtým vypočítané výsledky - memoizácia Dynamické programovanie Peter Trebatický et al. ProFIIT 2018 7.4.2018 33 / 41
1 Poradie Peter Trebatický 2 Heslá Michal Maňak 3 3 3 Peter Kmec 4 Logy Kamil Janeček 5 Binárna hra Veronika Žatková 6 Zaujímavé čísla - Márius Šajgalík Peter Trebatický et al. ProFIIT 2018 7.4.2018 34 / 41
Overovať všetky čísla na intervale <A, B>, či sú zaujímavé, je pomalé. Peter Trebatický et al. ProFIIT 2018 7.4.2018 35 / 41
Overovať všetky čísla na intervale <A, B>, či sú zaujímavé, je pomalé. Keďže nás ale zaujíma iba ich ciferný súčet, nemusíme ich overovať všetky. Peter Trebatický et al. ProFIIT 2018 7.4.2018 35 / 41
Overovať všetky čísla na intervale <A, B>, či sú zaujímavé, je pomalé. Keďže nás ale zaujíma iba ich ciferný súčet, nemusíme ich overovať všetky. Aby sme si uľahčili overovanie čísla, rozdelíme si pôvodný problém na dva podproblémy. Najprv spočítame počet zaujímavých čísel na intervale <0, B> a potom odpočítame počet zaujímavých čísel na intervale <0, A-1>. Peter Trebatický et al. ProFIIT 2018 7.4.2018 35 / 41
Overovať všetky čísla na intervale <A, B>, či sú zaujímavé, je pomalé. Keďže nás ale zaujíma iba ich ciferný súčet, nemusíme ich overovať všetky. Aby sme si uľahčili overovanie čísla, rozdelíme si pôvodný problém na dva podproblémy. Najprv spočítame počet zaujímavých čísel na intervale <0, B> a potom odpočítame počet zaujímavých čísel na intervale <0, A-1>. Vygenerujeme si všetky čísla s rovnakým počtom cifier ako horná hranica, ktoré majú usporiadané cifry od najmenšej po najväčšiu, pričom zľava podľa potreby dosadíme nuly. Napr. pre hornú hranicu intervalu 12345 vygenerujeme (nielen) číslo 00149. Peter Trebatický et al. ProFIIT 2018 7.4.2018 35 / 41
Overovať všetky čísla na intervale <A, B>, či sú zaujímavé, je pomalé. Keďže nás ale zaujíma iba ich ciferný súčet, nemusíme ich overovať všetky. Aby sme si uľahčili overovanie čísla, rozdelíme si pôvodný problém na dva podproblémy. Najprv spočítame počet zaujímavých čísel na intervale <0, B> a potom odpočítame počet zaujímavých čísel na intervale <0, A-1>. Vygenerujeme si všetky čísla s rovnakým počtom cifier ako horná hranica, ktoré majú usporiadané cifry od najmenšej po najväčšiu, pričom zľava podľa potreby dosadíme nuly. Napr. pre hornú hranicu intervalu 12345 vygenerujeme (nielen) číslo 00149. Keď takto vygenerujeme číslo (označme si X 0 ), ktoré má usporiadané cifry, musíme najprv overiť, či jeho cifry vieme rozdeliť na dve množiny, ktoré majú rovnaký súčet. Peter Trebatický et al. ProFIIT 2018 7.4.2018 35 / 41
To vieme spraviť technikou dynamického programovania, pričom stav definujeme ako dp[rozdiel medzi suctami mnozin][pocet spracovanych cifier] = (boolean)(vieme dosiahnut tento stav?). Peter Trebatický et al. ProFIIT 2018 7.4.2018 36 / 41
To vieme spraviť technikou dynamického programovania, pričom stav definujeme ako dp[rozdiel medzi suctami mnozin][pocet spracovanych cifier] = (boolean)(vieme dosiahnut tento stav?). Začíname v stave dp[0][0] a postupným prechádzaním cifier vygenerovaného čísla aktualizujeme stav. Teda keď si zoberieme ďalšiu cifru c ako k-tu v poradí, musíme sa pozrieť na všetky možné rozdiely r medzi dvoma množinami cifier, t.j. pozície dp[r][k], ktoré vieme dosiahnuť. Peter Trebatický et al. ProFIIT 2018 7.4.2018 36 / 41
To vieme spraviť technikou dynamického programovania, pričom stav definujeme ako dp[rozdiel medzi suctami mnozin][pocet spracovanych cifier] = (boolean)(vieme dosiahnut tento stav?). Začíname v stave dp[0][0] a postupným prechádzaním cifier vygenerovaného čísla aktualizujeme stav. Teda keď si zoberieme ďalšiu cifru c ako k-tu v poradí, musíme sa pozrieť na všetky možné rozdiely r medzi dvoma množinami cifier, t.j. pozície dp[r][k], ktoré vieme dosiahnuť. Pre všetky dosiahnuteľné stavy potom aktualizujeme dp[r + c][k + 1] = dp[r][k] ak r + c <= maximalny mozny rozdiel medzi mnozinami a dp[abs(r c)][k + 1] = dp[r][k], pričom maximalny mozny rozdiel medzi mnozinami vieme ohraničiť ako 9 (maximalny pocet cifier v cisle) 2 = 45. Peter Trebatický et al. ProFIIT 2018 7.4.2018 36 / 41
Keď takto vypočítame všetky stavy, pozrieme sa na hodnotu stavu dp[0][pocet cifier vygenerovaneho cisla], ktorý vyjadruje, či sa dajú cifry vygenerovaného čísla rozdeliť na dve množiny s rovnakým súčtom. Peter Trebatický et al. ProFIIT 2018 7.4.2018 37 / 41
Keď takto vypočítame všetky stavy, pozrieme sa na hodnotu stavu dp[0][pocet cifier vygenerovaneho cisla], ktorý vyjadruje, či sa dajú cifry vygenerovaného čísla rozdeliť na dve množiny s rovnakým súčtom. Implementačný detail: stači si pamätať len posledné dva stĺpce matice dp a namiesto nulovania jedného zo stĺpcov môžeme binárne hodnoty prvkov nahradiť hodnotou k + 1. Peter Trebatický et al. ProFIIT 2018 7.4.2018 37 / 41
Ak sa cifry vygenerovaného čísla (označme si X 0 ) dajú rozdeliť na dve množiny s rovnakým súčtom, musíme overiť, koľkými spôsobmi vieme preusporiadať jeho cifry tak, aby boli menšie ako horná hranica intervalu (označme si H). To vieme vypočítať ako počet takých permutácií s opakovaním, ktoré tvoria číslo menšie alebo rovné ako horná hranica. Peter Trebatický et al. ProFIIT 2018 7.4.2018 38 / 41
Permutácie s opakovaním P k0,k 1,...,k 9 (n) = n! k 0! k 1!... k 9! Keďže obmedzenie hornej hranice nám neovplyvňuje počet permutovaných cifier, menovateľ sa nám nezmení. Peter Trebatický et al. ProFIIT 2018 7.4.2018 39 / 41
Permutácie s opakovaním P k0,k 1,...,k 9 (n) = n! k 0! k 1!... k 9! Keďže obmedzenie hornej hranice nám neovplyvňuje počet permutovaných cifier, menovateľ sa nám nezmení. Môžeme teda najprv spočítať počet permutácií bez opakovania (takých čo sú menšie alebo rovné ako horná hranica) a výsledok dodatočne vydeliť menovateľom. Peter Trebatický et al. ProFIIT 2018 7.4.2018 39 / 41
Výpočet permutácií bez opakovania, ktoré sú menšie alebo rovné ako horná hranica Skúšame zaradom ukladať cifry od najvyššieho rádu. Peter Trebatický et al. ProFIIT 2018 7.4.2018 40 / 41
Výpočet permutácií bez opakovania, ktoré sú menšie alebo rovné ako horná hranica Skúšame zaradom ukladať cifry od najvyššieho rádu. Ak uložíme ďalšiu cifru, ktorá je menšia ako cifra rovnakého rádu v čísle H, všetky čísla X i, ktoré budú mať rovnaký prefix ako doposiaľ uložené číslo, budú menšie ako H. To znamená, že pre takto uloženú cifru jednoducho spočítame počet všetkých rôznych zakončení ako počet permutácií (bez opakovania) zvyšných cifier. Peter Trebatický et al. ProFIIT 2018 7.4.2018 40 / 41
Výpočet permutácií bez opakovania, ktoré sú menšie alebo rovné ako horná hranica Skúšame zaradom ukladať cifry od najvyššieho rádu. Ak uložíme ďalšiu cifru, ktorá je menšia ako cifra rovnakého rádu v čísle H, všetky čísla X i, ktoré budú mať rovnaký prefix ako doposiaľ uložené číslo, budú menšie ako H. To znamená, že pre takto uloženú cifru jednoducho spočítame počet všetkých rôznych zakončení ako počet permutácií (bez opakovania) zvyšných cifier. Ak uložíme ďalšiu cifru, ktorá je rovná ako cifra rovnakého rádu v čísle H, zafixujeme ju a rekurzívne pokračujeme ako v predchádzajúcom kroku na nižšom ráde so zvyšnými ciframi. Peter Trebatický et al. ProFIIT 2018 7.4.2018 40 / 41
Zdroje príkladov Poradie TopCoder Heslá TopCoder 3x3 Sphere Online Judge Logy CodeChef Binárna hra Veronika Žatková Zaujímavé čísla Sphere Online Judge Peter Trebatický et al. ProFIIT 2018 7.4.2018 41 / 41