Ako isto viete, nie každá kukurica je rovnaká. Niektoré odrody sú šťavnaté, iné majú zas obrovské obilky. Podaktoré sú dokonca aj dúhové!!! A povedzte mi, kto by už na svojom poli nechcel mať takúto biodiverzitu? Presne takto každoročne rozmýšľa aj Adam. Doteraz to mal pomerne jednoduché, na dedinskej burze vedel za výhodnú cenu jedného Trojkenu vykonať ľubovoľnú z barterových ponúk. Tento rok sa ale Americkým vedcom podarilo nevídané. Dokážu upravovať genetický kód kukurice, skoro úplne, ako sa im zachce[^1]! Dokonca si otvorili aj pobočku v Adamovej rodnej dedine, Kombajnovských Klasoviciach. Za svoje služby si neúčtujú nič menej ako jeden Trojken. Pomôžte Adamovi zistiť, koľko najmenej Trojkenov musí zaplatiť za to, aby z jeho nudnej odrody kukurice získal nejakú zaujímavejšiu.
Každá odroda kukurice sa dá jednoznačne určiť jej genetickým kódom
ako reťazec, ktorý sa skladá len z písmen L a
R (môže byť aj prázdny). Za jeden Trojken dokáže genetické
laboratórium v Kombajnovských Klasoviciach odstrániť gén na konci
genetického kódu nejakej odrody alebo pridať na koniec ľubovoľný z génov
L a R. Na burze taktiež existuje $n$ barterových ponúk, ktoré sa vzťahujú na
odrody $a_i$ a $b_i$. Za vykonanie jednej výmeny zaplatí
Adam jednej Trojken a môže vymeniť odrodu $a_i$ za odrodu $b_i$ alebo naopak. Adama by zaujímalo
$q$ scenárov, v ktorých začína s
odrodou s genómom $z_i$ a chcel by
skončiť s genómom $k_i$. Zistite,
koľko najmenej Trojkenov ho to môže stáť.
V prvom riadku vstupu sú čísla $n$ a $q$ $(0 \leq n \leq 10^3, 1 \leq q \leq 10^4)$ udávajúce počet barterových ponúk na burze a počet scenárov, na ktoré Adama zaujíma odpoveď. V ďalších $n$ riadkoch sa na každom nachádzajú $2$ reťazce $a_i$ a $b_i$, ktoré hovoria, že odroda s genómom $a_i$ sa dá vymeniť za odrodu s genómom $b_i$ za zaplatenie $1$ Trojkenu a naopak. Nasleduje $q$ riadkov, na každom z nich sa nachádzajú $2$ reťazce $z_i$ a $k_i$. Pre každý riadok vypíšte, koľko najmenej Trojkenov treba zaplatiť na to, aby Adam z odrody $z_i$ dostal odrodu $k_i$.
Všetky reťazce genómov na vstupe sa skladajú len z písmen
L a R a obsahujú aspoň jedno písmeno. Existuje
ale aj kukurica s prázdnym genómom.
Označme si $D$ najväčšiu dĺžku reťazca na vstupe. Potom pre všetky sady platí, že $(n+q) \cdot D \leq 2 \cdot 10^6$.
V jednotlivých sadách navyše platia nasledujúce obmedzenia:
| Sada | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| MATH_STASH_26_ENDSTASH | MATH_STASH_27_ENDSTASH | MATH_STASH_28_ENDSTASH | MATH_STASH_29_ENDSTASH | MATH_STASH_30_ENDSTASH |
| MATH_STASH_31_ENDSTASH | MATH_STASH_32_ENDSTASH | MATH_STASH_33_ENDSTASH | MATH_STASH_34_ENDSTASH | MATH_STASH_35_ENDSTASH |
| MATH_STASH_36_ENDSTASH | MATH_STASH_37_ENDSTASH | MATH_STASH_38_ENDSTASH | MATH_STASH_39_ENDSTASH | MATH_STASH_40_ENDSTASH |
Keďže je vstup veľmi veľký, odporúčame v jazyku C++
použiť rýchle načítavanie vstupu
cin.tie(0)->sync_with_stdio(0) a namiesto
endl používať '\n'.
Vypíšte $q$ riadkov, na $i$-tom z nich, koľko najmenej Trojkenov treba zaplatiť na to, aby Adam získal zo začiatočnej odrody koncovú.
Input:
2 2
R LL
RR RLR
LLL RLR
RRL RLR
Output:
4
2
V prvom scenári jedna z najlacnejších možností môže vyzerať
napríklad takto. Najprv odstránime posledný gén, čím dostaneme odrodu
LL. Tú dokážeme za jeden Trojken zmeniť za odrodu
R. Potom už len stačí pridať postupne gény L a
R. Celkovo zaplatíme 4 Trojkeny. V druhom scenári vyzerá
najlacnejšia možnosť takto. Najprv odstránime posledný gén a potom
vymeníme odrodu RR za odrodu RLR. Takto
zaplatíme 2 Trojkeny.
Input:
0 1
LLR LR
Output:
3
Je zbytočné na začiatku pridávať nejaké gény na koniec, keďže
neexistujú žiadne barterové ponuky. Preto je optimálne 2-krát odstrániť
posledný gén a raz pridať gén R na koniec, čo stojí spolu 3
Trojkeny.
Keďže sa na vstupe dokopy nachádza $O((n+q)D)$ znakov, tak časová zložitosť načítavania vstupu bude pri všetkých riešeniach $O((n+q)D)$, preto ju už ďalej pri odhade časovej zložitosti nebudeme spomínať.
predstaviť?
Celú úlohy si vieme reprezentovať ako hľadanie najkratšej cesty v nejakom neorientovanom grafe. Vrcholy tohto grafu budú jednotlivé odrody a hrany budú medzi odrodami $a$ a $b$ práve vtedy, ak sa dá zmeniť odroda $a$ za odrodu $b$ zaplatením $1$ trojkenu. Hrany v tomto grafe si vieme rozdeliť na $2$ skupiny: hrany, ktoré vznikli kvôli barterovým ponukám a hrany, ktoré vznikli kvôli laboratóriu.
Hrany, ktoré vznikli kvôli laboratóriu (označme si ich
stromové) sa v rôznych vstupoch nelíšia. A čo viac, keď sa
pozrieme na graf, ktorý obsahuje len tieto hrany, tak dostaneme binárny
strom, ktorý je zakorenený vo vrchole reprezentujúcom prázdny genóm.
Ľavý syn nejakého vrchola reprezentuje genóm, ktorý vznikol pridaním
L na koniec aktuálneho genómu a pravý syn reprezentuje
genóm, ktorý vznikol pridaním R.
Najprv si môžeme všimnúť, že sa nikdy neoplatí mať odrodu, ktorej genóm má dĺžku väčšiu ako $D$. Teda nám stačí vygenerovať graf obsahujúci všetkých $O(2^D)$ vrcholov. Keďže je najdlhšia dĺžka reťazca v prvej podúlohe pomerne malá, tak nám stačí si ho celý zapamätať a pre každú otázku pomocou prehľadávania do šírky nájsť najkratšiu cestu.
Náš graf má $O(2^D)$ vrcholov a dokopy $O(2^D + n)$ hrán, teda celková časová zložitosť pre jednu otázku bude $O(2^D + n)$.
Časová zložitosť predpočitania bude $O(nD \log{n})$ alebo $O(2^D)$ v závislosti od implementácie.
Ak by sa v úlohe nenachádzali žiadne barterové ponuky, tak cesta medzi ľubovoľnými vrcholmi $a$ a $b$ by vyzerala pomerne jednoducho. Najprv pôjdeme z vrcholu $a$ smerom hore do ich najnižšieho spoločného predka (alebo aj v skratke LCA) a potom z tohto predka smerom dole do vrcholu $b$.
Ako bude vyzerať nejaká cesta z vrcholu $a$ do vrcholu $b$ v grafe, kde sú aj hrany reprezentujúce barterové ponuky? Povedzme, že postupne použijeme barterové hrany $b_1, b_2, ..., b_k$. Potom medzi koncom jednej a začiatkom ďalšej hrany bude cesta prechádzať len cez stromové hrany, teda pôjde hore do ich najnižšieho spoločného predka a potom dole.
Označme si teda vrcholy, ktoré sú konce nejakej barterovej hrany alebo sú súčasťou nejakej otázky ako zaujímavé. Ako sme si vyššie ukázali, tak nám stačí medzi každou dvojicou zaujímavých vrcholov vedieť zistiť najkratšiu cestu, ktorá prechádza len cez stromové hrany. Táto cesta pôjde cez ich najmenšieho spoločného predka. Keďže najnižší spoločný predok dvoch zaujímavých vrcholov sa nachádza niekde na ceste z jedného vrchola do koreňa, tak optimálna cesta medzi zaujímavými vrcholmi bude určite prechádzať len cez vrcholy, ktoré sú predkami aspoň jedného z nich.
Tu sa nám črtá trošku lepšie riešenie. Budeme sa pozerať na graf, ktorý obsahuje len zaujímavé vrcholy a vrcholy, ktoré sú predkami nejakého zaujímavého vrchola. Koľko ich bude? Každý vrchol je v hĺbke najviac $D$, teda má nad sebou najviac $D$ vrcholov. Takýto graf teda bude mať $O((n + q)D)$ vrcholov a $O((n + q)D)$ hrán. Ak v ňom budeme zas hľadať cesty pomocou prehľadávania do šírky, tak na jednu otázku vieme odpovedať v čase $O((n + q)D)$ s predpočítaním v čase $O(nD)$.
odstrániť
Povedzme, že si medzi zaujímavé vrcholy pridáme LCA všetkých dvojíc na začiatku zaujímavých vrcholov. Keďže najkratšie cesty po stromových hranách idú len hore po LCA, tak pre každý zaujímavý vrchol nám stačí len pridať hranu medzi ním a prvým zaujímavým vrcholom, ktorý je nad ním. Takto sa vieme dostať z jedného zaujímavého vrcholu do druhého po stromových hranách rovnakou cestou, ako predtým, teda sme týmto nič nepokazili.
Koľko vrcholov ale musíme pridať? Predstavme si, že máme na začiatku
v poli $k$ zaujímavých vrcholov.
Zoberme si teraz $2$ vrcholy $a$ a $b$, ktorých LCA (označme si ho $L$) sa nachádza najhlbšie v strome. V
podstrome vrcholu $L$ sa nemôže
nachádzať žiaden iný vrchol (okrem $a$ a $b) z nášho poľa, lebo by to bolo v
spore s tým, že $L$ je najhlbšie LCA
vrcholov z poľa. Preto pre ľubovoľný iný vrchol $c$ bude platiť, že $LCA(c,a) = LCA(c,b) = LCA(c,L)$. Preto
môžeme $a$ a $b$ z poľa vymazať a vložiť tam $L$. V každom takomto kroku sa zníži počet
prvkov v poli o $1$, teda nových
zaujímavých vrcholov môžeme pridať najviac $O(k)$. V asymptotickej časovej zložitosti
sa nám teda nič nezhorší tým, keď tieto vrcholy pridáme medzi
zaujímavé!
Vieme teda, že zaujímavých vrcholov bude spolu najviac $O(n+q)$ a hrán medzi nimi tiež $O(n+q)$. Keď sa nám už nejak podarí
vytvoriť tento graf, tak pre každú otázku len stačí pomocou Dijkstry
(lebo hrany teraz nemajú všetky dĺžku $1$) zistiť vzdialenosť konca a začiatku v
čase $O((n+q) \log{(n+q)}$.
#### Predpočítanie
Vrcholy budeme vkladať do písmenkového stromu (trie). Začneme so
všetkými genómami v koreni. Keď sme v nejakom vrchole trie s nejakou
množinou genómov, tak si ju vieme rozdeliť v lineárnom čase od ich počtu
na tie, ktoré končia v tomto vrchole, ktoré idú do ľavého podstromu a
ktoré do pravého. Kedy je vrchol trie zaujímavý? Ak sa vo vrchole končí
nejaký genóm, tak určite je zaujímavý, lebo je to koniec nejakej hrany
alebo súvisí z nejakou otázkou. Ak nejaké vrcholy patria do jeho ľavého
aj pravého podstromu, tak bude tiež zaujímavý, keďže bude LCA nejakej
dvojice vrcholov. Inak je nezaujímavý. Keď si takto rekurzívne spočítame
všetky zaujímavé vrcholy, tak sa dá aj jednoducho zistiť, ako vyzerajú
hrany medzi nimi. Vždy si len stačí do rekurzívneho volania posielať aj
rodiča aktuálneho vrchola a jeho hĺbku.
Toto celé vieme predpočítať v čase $O((n+q)D)$, lebo v každej z $D$ vrstiev trie sa nachádza v súčte
najviac $n+q$ prvkov a v každej
úrovni vykonáme prácu priamo úmernú počtu prvkov v nej.
### Rýchlejšie otázky
V predošlom riešení sme si medzi zaujímavé vrcholy pridali všetkých
$O(q)$ vrcholov, ktoré sa vzťahujú na
otázky. Každý z nich ale využijeme len v tej jednej otázke, ku ktorej sa
vzťahujú a inak sú zbytočné. Skúsme teda vrcholy $z_i$ a $k_i$ pridať medzi zaujímavé len počas
danej otázky a potom ich odstrániť.
Ako teraz zistiť odpovede na jednotlivé otázky? Keď budeme hľadať
nejaký genóm $x$ v našej trie
zaujímavých vrcholov, tak niekedy narazíme na hranu, na ktorej sa
prestane v nejakom znaku zhodovať (ak taká neexistuje, tak to znamená,
že $x$ je v trii a netreba riešiť
žiadne špeciálne prípady). Nech táto hrana ide z vrcholu $a$ do vrcholu $b$. Teraz nám stačí pridať hrany z $x$ do $a$ a z $x$ do $b$ so správnou dĺžkou a máme graf, ktorý
správne reprezentuje aktuálnu situáciu. Keď toto spravíme pre $z_i$ a $k_i$, tak len znova stačí pomocou Dijkstry
zistiť ich vzdialenosť.
Keďže graf zaujímavých vrcholov teraz bude mať len $O(n)$ vrcholov, tak odpovedať na otázku
vieme v čase $O(n \log{n})$.
Predpočítanie sa nám nijak nezhoršilo. Finálna časová zložitosť je teda
$O(nD)$ na predpočítanie a $O(n \log{n})$ na otázku.
```c++
#include
Korešpondenčný seminár z programovania zastrešuje občianske združenie Trojsten.
Trojsten, o.z.
FMFI UK, Mlynská dolina
842 48 Bratislava
Programátorská súťaž pre základoškolákov
Materiály a úlohy na výučbu programovania
Intenzívny programátorský zážitok v lete