QOJ.ac

QOJ

时间限制: 3 s 内存限制: 1024 MB 总分: 100 可 Hack ✓

#16889. Optymalizacja NPU

统计

Firma Furiosa AI tworzy jednostki NPU (Neural Processing Unit), które pozwalają na szybsze uczenie i wnioskowanie modeli sztucznej inteligencji niż tradycyjne jednostki przetwarzające. Programy działające na typowych jednostkach przetwarzających wykorzystują dane zapisane na hoście, przetwarzając je za pomocą różnych operatorów w celu obliczenia pożądanych wartości. W tym zadaniu upraszczamy ten proces, rozważając następujące środowisko:

  • Host posiada przestrzeń do przechowywania $1\,000\,000$ danych, a każda komórka jest ponumerowana od $0$ do $999\,999$.
  • Każdy operator przyjmuje co najmniej jedną daną wejściową i oblicza jedną daną wyjściową. Operatory również są ponumerowane liczbami od $0$ do $999\,999$.
  • Program jest wyrażony za pomocą następującej notacji BNF (Backus-Naur Form):

    <number> ::= 0 | 1 | ... | 999999 <value> ::= <number> | <number>(<list>) <list> ::= <value> | <list>,<value>

  • Program oblicza jedną wartość. Oznacza to, że program jest ciągiem znaków odpowiadającym <value>.

  • Wartość <value> obliczana jest w następujący sposób:
    • Jeśli <value> jest wyrażone jako <number>, jest to dana zapisana w komórce o numerze <number> na hoście przed uruchomieniem programu.
    • Jeśli <value> jest wyrażone jako <number>(<list>), jest to dana wyjściowa obliczona przy użyciu operatora o numerze <number>, gdzie wartości <value> wewnątrz <list> są kolejno danymi wejściowymi.
  • W jednym programie ten sam <number> nie pojawia się wielokrotnie.

NPU opracowywane przez Furiosa AI może wykonywać ten sam program szybciej niż zwykła jednostka przetwarzająca, ale wymaga to kompilatora, który skompiluje program na instrukcje niskiego poziomu używane przez NPU. Ponieważ zużycie pamięci i czas wykonania programu zmieniają się w zależności od sposobu kompilacji, potrzebny jest zoptymalizowany kompilator, aby efektywnie korzystać z NPU.

NPU posiada pamięć, w której można przechowywać $M$ danych, a każda komórka pamięci jest ponumerowana od $0$ do $M-1$. NPU obsługuje trzy rodzaje instrukcji:

  • a >> b
    • Kopiuje daną z komórki $a$ hosta do komórki $b$ pamięci. ($0 \le a < 1\,000\,000$; $0 \le b < M$). Jeśli dane już tam istnieją, zostają nadpisane.
  • a << b
    • Kopiuje daną z komórki $b$ pamięci do komórki $a$ hosta. ($0 \le a < 1\,000\,000$; $0 \le b < M$). Jeśli dane już tam istnieją, zostają nadpisane.
  • o = w | m1 m2 ... ml
    • Oblicza wynik operatora $w$, używając wartości z adresów pamięci $m_1, m_2, \dots, m_l$ jako kolejnych danych wejściowych, i zapisuje wynik w komórce $o$ pamięci.
    • Komórka, w której zapisywany jest wynik, musi być różna od komórek, w których przechowywane są dane wejściowe. Oznacza to, że $o \neq m_i$ ($1 \le i \le l$).

Program NPU to sekwencja powyższych instrukcji; po uruchomieniu programu instrukcje są wykonywane jedna po drugiej.

Efektywność programu zależy od wielu czynników, ale jeśli liczba użytych instrukcji jest mała, istnieje duże prawdopodobieństwo, że program jest wydajny. Mając dany ciąg znaków odpowiadający <value>, przekształć go w program NPU, który oblicza wartość <value> przy użyciu jak najmniejszej liczby instrukcji i zapisuje wynik w komórce pamięci $0$.

Wejście

W pierwszej linii podana jest wielkość pamięci NPU $M$. ($1 \le M \le 1\,000\,000$) W drugiej linii podany jest ciąg znaków odpowiadający <value>, który należy obliczyć. Długość tego ciągu wynosi co najwyżej $1\,000\,000$.

Wyjście

Jeśli pamięć NPU jest zbyt mała, aby skompilować program, wypisz $-1$. Jeśli program można skompilować, w pierwszej linii wypisz minimalną liczbę instrukcji potrzebną do obliczenia <value>. Od następnej linii wypisz instrukcje tworzące program, po jednej w każdej linii, w kolejności wykonywania. Wszystkie tokeny w instrukcji muszą być oddzielone pojedynczymi spacjami.

Jeśli istnieje wiele rozwiązań, wypisz dowolne z nich.

Przykład

Wejście 1

7
71(72(41,42),73(43,44))

Wyjście 1

7
41 >> 3
42 >> 4
43 >> 5
44 >> 6
1 = 72 | 3 4
2 = 73 | 5 6
0 = 71 | 1 2

Wejście 2

3
71(72(41,42),73(43,44))

Wyjście 2

9
43 >> 2
44 >> 0
1 = 73 | 2 0
59 << 1
41 >> 2
42 >> 0
1 = 72 | 2 0
59 >> 2
0 = 71 | 1 2

Wejście 3

2
71(72(41,42),73(43,44))

Wyjście 3

-1

Discussions

About Discussions

The discussion section is only for posting: General Discussions (problem-solving strategies, alternative approaches), and Off-topic conversations.

This is NOT for reporting issues! If you want to report bugs or errors, please use the Issues section below.

Open Discussions 0
No discussions in this category.

Issues

About Issues

If you find any issues with the problem (statement, scoring, time/memory limits, test cases, etc.), you may submit an issue here. A problem moderator will review your issue.

Guidelines:

  1. This is not a place to publish discussions, editorials, or requests to debug your code. Issues are only visible to you and problem moderators.
  2. Do not submit duplicated issues.
  3. Issues must be filed in English or Chinese only.
Active Issues 0
No issues in this category.
Closed/Resolved Issues 0
No issues in this category.