Zadanie

“Dalo by sa pohnúť?”

“Kto ti dal vodičák?”

“Slečna ja Vás zveziem, moje auto je dosť veľké…”

“Ľudiaaa? Nevideli ste niekto jeden valec z môjho auta?”

“Čo to bola za značka? Nebolo to Daj prednosť v jazde?”

“Odtiahnete ma niekto? Asi som zase prerazil olejovú vaňu…”

“Joooj, posunúť sa, aby som mohol odísť? Dalo by sa?”

“Dávam Vám ešte 2 minúty, a potom sa proste pohnem tým smerom, ako stojím.”

“Vajcia? Ja som naozaj do auta nebalila vajcia! Tie musí mať niekto iný, ja ich určite nemám”

Osadenstvo T21 tento hluk spočiatku ignorovalo, ale ako neutíchal, postupne sa preberali z letargie a knedliačenia na gaučoch. Hneď ako vstali a pozreli sa z okna, pochopili čo sa stalo. FKS odchádza na sústredenie. A všetci vedúci išli vlastným autom. Pred sústredkom sa všetci stretli na matfyze a zastali autom pred okno T2, na jednu dlhú a úzku cestu. Po čase do áut pobalili veci, a ako už chceli všetci odísť, tak zistili, že nikto sa nie je ochotný autom otočiť, každý chce pokračovať tým smerom, ako teraz stojí.

Aby mali na túto situáciu pamiatku, Adam zobral foťák a odfotil všetky autá, ktoré boli na ceste. Hneď potom sa ale stali naraz dve veci: zapípala mikrovlnka (a všetci sa k nej otočili) a autá sa pohli (a teda do seba ponarážali). Keďže nikto z osadenstva T2 sa na autá nepozeral, tak nikto nevidel priebeh zrážky, ktorá nastala.

Po čase smútenia (nad tým, že nevideli zrážku, nie nad autami) si ale uvedomili, že možno by sa dalo aspoň z fotky povedať, koľko zrážok sa pred oknom udialo. Vedeli by ste im to zistiť?

Úloha

Vašou úlohou bude určiť počet zrážok, ktoré nastali pred oknom T2. Pred T2 oknom sa nachádzajú autá, ktoré buď smerujú doľava, stoja, alebo smerujú doprava. Všetky autá, ktoré smerujú doľava alebo doprava sa v rovnakom momente pohli rovnakou rýchlosťou. Vašou úlohou je zistiť počet zrážok, ktoré nastanú. Autá po zrážke zastanú na mieste a ostanú stáť.

Zrážka nastane vtedy, keď hýbajúce sa auto do niečoho narazí (teda ak narazí auto do stojaceho auta, je to jedna zrážka, ak sa čelne zrazia dve autá, čo doteraz išli opačne, sú to 2 zrážky).

Formát vstupu

Na jedinom riadku vstupu dostanete \(n\) znakov dlhý reťazec. Tento reťazec sa skladá zo znakov > (doprava idúce auto), < (doľava idúce auto), = (stojace auto).

V jednotlivých sadách platia nasledujúce obmedzenia:

Sada 1 2 3 4
\(1 \leq n \leq\) 5 \(1\,000\) \(1\,000\,000\) \(5\,000\,000\)

V prvej a druhej sade sa nevyskytujú stojace autá.

V prvej sade sa všetky autá okrem jedného hýbu rovnakým smerom (napríklad <<<><, alebo ><<<<<).

Formát výstupu

Vypíšte jediný riadok, počet zrážok, ktoré pred oknami T2 nastanú. Nezabudnite za číslom vypísať znak nového riadku.

Príklady

Input:

><><

Output:

4

Input:

<=>

Output:

0

Krajné autá odídu a stredné sa nikam nepohne, takže nenastane žiadna zrážka

Input:

>>=<><

Output:

5

Input:

>>><><<><<>>==<>==<><<>><><>=><=

Output:

26

  1. KSP miestosť na matfyze↩︎

Našou úlohou bolo spočítať počet zrážok, ktoré nastanú. Vieme, že za zrážku sa ráta všetko, kde idúce auto narazí do niečoho. Vieme tiež, že všetky autá po zrážke ostanú stáť.

Pomalé riešenie

Prvou možnosťou je pre každé auto, ktoré sa niektorým smerom hýbe (doprava alebo doľava) sa pozrieť, či má do čoho naraziť. Naraziť má do čoho vtedy, keď sa tým smerom, ktorým sa hýbe, nachádza auto, ktoré stojí, alebo smeruje opačne. Takže pre každé auto sa pozrieme, či má do čoho naraziť a spočítame tieto zrážky.

Pre každé auto (ktorých je \(n\)), pozrieme prinajhoršom všetky ostatné autá (ktorých je \(n\)), takže spolu urobíme \(O(n^2)\) operácií.

Časová zložitosť je \(O(n^2)\), a pamäťová \(O(n)\), lebo okrem vstupného poľa si nič nemusíme pamätať.

auta = input()

zrazky = 0

for i in range(len(auta)):
	if auta[i]=='>':
		for j in range(i+1, len(auta)):
			if auta[j]!='>':
				zrazky+=1
				break
	elif auta[i]=='<':
		for j in range(i-1, -1, -1):
			if auta[j]!='<':
				zrazky+=1
				break

print(zrazky)
#include<iostream>
#include<string>

using namespace std;

int main(){
	string auta;
	cin >> auta;
	
	long long zaciatok, koniec, zrazky=0;
	
	for(long long i=0; i<=auta.size(); i++){
        int smer = 0;
        if(auta[i]=='<')
            smer = -1;
        if(auta[i]=='>')
            smer = 1;
        
        long long j=i+smer;
        while(smer!=0 && j>=0 && j<auta.size()){
            if(auta[i]!=auta[j]){
                zrazky++;
                break;
            }
            j += smer;
        }
	}
	
	cout<<zrazky<<endl;
	
	return 0;
}

Vzorové riešenie

Je pomerne jasné, že ak auto, ktoré je na ľavej strane, smeruje doľava, tak do ničho nenarazí. Rovnako je to aj na pravej strane s autom, ktoré smeruje doprava. Môžeme si uvedomiť, že to ale neplatí len pre autá, ktoré sú úplne na kraji, ale aj pre všetky autá, ktoré sú naľavo (tým myslíme také, že naľavo od nich sú len autá, ktoré smerujú doľava), a smerujú doľava. Analogicky to platí aj pre autá, ktoré sú napravo. Napríklad, ak máme autá:

<<<>=<>>

Tak vieme povedať, že ľavé 3 autá a pravé 2 autá určite do ničoho nenarazia, iba pekne za sebou odídu preč.

To znamená, že nás nezaujíma súvislý úsek áut, ktoré sú naľavo a smerujú doľava, a súvislý úsek áut napravo, ktoré smerujú doprava.

Z nášho príkladu vyššie nás teda zaujímajú iba tieto autá:

>=<

Čo vieme povedať, o zrážkach, ktoré nastanú v tejto strednej časti?

Vieme, že každé auto, ktoré nestojí musí do niečoho naraziť. Prečo? Lebo jediná iná možnosť je, že by odišlo preč, a nikdy do ničoho nenarazilo, ale to sa nemôže stať, keďže také autá sú naľavo, a smerujú doľava, alebo napravo a smerujú doprava, a tie ignorujeme.

Vzorové riešenie teda najprv zistí, ktorý úsek áut nás presne zaujíma, teda zistí aký dlhý je úsek áut, ktoré sú naľavo a smerujú doľava. To isté urobí aj pre pravú stranu. Následne pre každé auto v strednej časti, ktoré nestojí, pripočíta \(1\) k výslednému počtu zrážok, a vypíše tento výsledok.

Toto riešenie prejde celé pole práve raz, a teda jeho časová zložitosť je \(O(n)\). Pamätať si stále musíme len celé pole, teda pamäťová zložitosť je tiež \(O(n)\).

auta = input()

for zaciatok in range(len(auta)):
    if auta[zaciatok]!='<':
        break

for koniec in range(len(auta)-1, -1, -1):
    if auta[koniec]!='>':
        break

zrazky = 0

for i in range(zaciatok, koniec+1):
    if auta[i]!='=':
	    zrazky += 1

print(zrazky)
#include<iostream>
#include<string>

using namespace std;

int main(){
	string auta;
	cin >> auta;
	
	long long zaciatok, koniec, zrazky=0;
	
	for(zaciatok=0; zaciatok<auta.size(); zaciatok++){
		if(auta[zaciatok]!='<')
			break;
	}
	
	for(koniec=auta.size()-1; koniec>=0; koniec--){
		if(auta[koniec]!='>')
			break;
	}
	
	for(long long i=zaciatok; i<=koniec; i++){
        if(auta[i]!='=')
            zrazky++;
	}
	
	cout<<zrazky<<endl;
	
	return 0;
}

Vzorovejšie riešenie (v konštantnej pamäti)

Existuje aj riešenie v konštantnej pamäti. Jeho kľúčovou myšlienkou je, že ak ideme po vstupom poli áut, tak vždy keď nájdeme auto, ktoré smeruje doľava (<), tak vieme, že všetky autá naľavo od neho, ktoré idú doprava do niečoho narazia. V prípade, že nájdeme auto, ktoré smeruje doprava, tak si iba musíme poznačiť, že sme ho niekde videli. No a v prípade, že nájdeme auto, ktoré stojí na mieste, tak vieme, že všetky autá, čo sme videli, a smerovali doprava tiež majú do čoho naraziť.

Diskusia

Tu môžte voľne diskutovať o riešení, deliť sa o svoje kusy kódu a podobne.

Pre pridávanie komentárov sa musíš prihlásiť.