QOJ.ac

QOJ

実行時間制限: 3 s メモリ制限: 1024 MB 満点: 100 ハック可能 ✓

#16889. NPU最適化

統計

Furiosa AIでは、人工知能モデルの学習および推論を従来の処理ユニット(processing unit)よりも高速に行えるNPU(Neural Processing Unit)を開発している。一般的な処理ユニットで動作するプログラムは、ホスト(host)に保存されたデータを様々な種類の演算子を用いて処理し、目的の値を計算する。この問題では、この過程を単純化し、次のような環境を考える。

  • ホストには $1\,000\,000$ 個のデータを保存できる空間があり、各空間には $0$ 番から $999\,999$ 番までの番号が付けられている。
  • 各演算子は1つ以上の入力データを受け取り、1つの出力データを計算する。演算子にも $0$ 以上 $999\,999$ 以下の番号が付けられている。
  • プログラムは次のようなBNF(Backus-Naur Form)で表現される。

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

  • プログラムは1つの値を計算する。つまり、プログラムは <value> に該当する文字列である。

  • <value> の値は次のように計算される。
    • <value><number> で表現される場合、プログラム開始前のホストの <number> 番空間に保存されているデータである。
    • <value><number>(<list>) で表現される場合、<list> 内の <value> たちを順に入力データとして、<number> 番の演算子を使用して計算した出力データである。
  • 1つのプログラム内に同じ <number> が複数回登場することはない。

Furiosa AIが開発するNPUは、同じプログラムを一般的な処理ユニットよりも高速に実行できるが、そのためにはプログラムをNPUが使用する低レベルの命令セットに再コンパイルするコンパイラが必要である。同じプログラムであっても、どのようにコンパイルするかによってプログラムのメモリ使用量や実行時間が変わるため、効率的にNPUを使用するには最適化されたコンパイラが必要となる。

NPUには $M$ 個のデータを保存できるメモリがあり、メモリの各空間には $0$ 番から $M-1$ 番までの番号が付けられている。NPUは次の3種類の命令をサポートする。

  • a >> b
    • ホストの a 番データをメモリの b 番空間にコピーする。($0 \le a < 1\,000\,000$; $0 \le b < M$) データが既に存在する場合は上書きされる。
  • a << b
    • メモリの b 番データをホストの a 番空間にコピーする。($0 \le a < 1\,000\,000$; $0 \le b < M$) データが既に存在する場合は上書きされる。
  • o = w | m1 m2 ... ml
    • メモリの $m_1, m_2, \dots, m_l$ 番地にある値を順に入力データとする $w$ 番演算子の出力データを、メモリの $o$ 番空間に保存する。
    • 出力データが保存される空間は、入力データが保存されている空間と異なっていなければならない。つまり、$o \neq m_i$ ($1 \le i \le l$) でなければならない。

NPUプログラムは上記の命令の並びであり、プログラムを実行すると、プログラムを構成する命令が順に実行される。

プログラムの効率は様々な要因によって決定されるが、使用する命令数が少なければ効率的なプログラムである可能性が高い。<value> に該当する文字列が与えられたとき、命令を可能な限り少なく使用して <value> の値を計算し、メモリの $0$ 番に保存するNPUプログラムに変換してみよう。

入力

最初の行にはNPUのメモリサイズ $M$ が与えられる。($1 \le M \le 1\,000\,000$)

2行目には計算すべき <value> に該当する文字列が与えられる。この文字列の長さは $1\,000\,000$ 以下である。

出力

NPUのメモリが不足しておりプログラムをコンパイルできない場合は $-1$ を出力する。

プログラムをコンパイルできる場合は、最初の行に命令を最小限に使用して <value> を計算するプログラムの命令数を出力する。次の行から、プログラムを構成する命令を1行に1つずつ順に出力する。1つの命令のすべてのトークンの間には空白を1つずつ入れる。

複数の答えが可能な場合は、そのうちのどれか1つを出力すればよい。

入出力例

入力 1

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

出力 1

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

入力 2

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

出力 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

入力 3

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

出力 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.