難易度評価

難易度を1〜10段階で評価できます。投票はあとから変更・取り消しできます。

難易度(投票) Lv.5.0 (2票)

投票の分布
  1. Lv.10票
  2. Lv.20票
  3. Lv.30票
  4. Lv.40票
  5. Lv.52票
  6. Lv.60票
  7. Lv.70票
  8. Lv.80票
  9. Lv.90票
  10. Lv.100票

難易度の目安を見る ↗

ログインして難易度を投票

外部サイトへ移動します

リンク先の URL を確認してから開いてください。

別タブで開く

XOR Divisor Sugoroku

作成者 yuki4869

難易度(作成者設定) Lv.5

難易度(投票) Lv.5.0 (2票)

実行時間制限
3 秒
メモリ制限
512 MiB

解説

この解説では、xx 自身を除く xx の約数を xx の 真の約数、xx 自身を除く xx の倍数を xx の 真の倍数 と呼びます。

各クエリについて XX から 11 までの移動方法をすべて調べるのは困難です。そこで、すべての xx について、xx から 11 まで移動したときに実現できる XOR の値をあらかじめ求めます。

移動を逆向きに考える

問題では、現在いる整数を xx とすると、xx の真の約数 dd へ移動できます。すなわち、

 x→d(d∣x, d\<x) \ x\to d \qquad (d\mid x,\ d\<x)\

という移動が可能です。

これを逆向きに見ると、d→xd\to x と移動できるのは、xx が dd の真の倍数であるときです。したがって、整数 dd から移動できる整数は

 2d,3d,4d,… \ 2d,3d,4d,\ldots\

です。

また、XOR は計算する順番を入れ替えても値が変わりません。したがって、

 X→⋯→1 \ X\to\cdots\to1\

という経路を逆向きにした

 1→⋯→X \ 1\to\cdots\to X\

を考えても、経路上の AiA_i の XOR は同じです。

よって、整数 11 から各整数 xx へ向かう方向に DP を行います。

DP の定義

check[x][v]\mathrm{check}[x][v] を、

11 から xx まで真の倍数へ移動する経路のうち、経路上の整数に書かれた値の XOR を vv にできるものが存在するか

を表す bool 値とします。

0≤Ai<640\le A_i<64 であるため、いくつ XOR を取っても値は 00 以上 6363 以下です。したがって、各 xx について考える必要がある vv は 6464 通りだけです。

DP の初期値

x=1x=1 のとき、通っている整数は 11 だけなので、

 check[1][A_1]=true \ \mathrm{check}[1][A\_1]=\mathrm{true}\

とします。それ以外の状態はすべて false で初期化します。

DP の遷移

整数 xx について、

 check[x][v]=true \ \mathrm{check}[x][v]=\mathrm{true}\

であるとします。

xx の真の倍数 yy へ移動すると、新たに整数 yy を通るため、XOR に AyA_y が追加されます。したがって、

 check[y][v⊕A_y]=true \ \mathrm{check}[y][v\oplus A\_y]=\mathrm{true}\

と遷移できます。

xx の真の倍数は 2x,3x,4x,…2x,3x,4x,\ldots なので、実装では次のように列挙できます。

for (int x = 1; x <= N; x++) {
    for (int y = 2 * x; y <= N; y += x) {
        for (int v = 0; v < 64; v++) {
            if (check[x][v]) {
                check[y][v ^ A[y]] = true;
            }
        }
    }
}

常に x<yx<y が成り立つため、xx の小さい順に処理すれば、遷移元の状態はすでに確定しています。

クエリへの回答

クエリ (X,Y)(X,Y) を考えます。

check[X][v]=true\mathrm{check}[X][v]=\mathrm{true} である vv は、XX から 11 まで移動したときに実現できる XOR の値です。この経路を選んだときのスコアは

 Y⊕v \ Y\oplus v\

です。

したがって、答えは

 min⁡_check[X][v]=true(Y⊕v) \ \min\_{\mathrm{check}[X][v]=\mathrm{true}}(Y\oplus v)\

です。

vv は 00 以上 6363 以下なので、各クエリについて 6464 通りすべてを試せばよいです。

計算量

整数 xx からは、その真の倍数 2x,3x,4x,… 2x,3x,4x,\ldots へ遷移します。

したがって、倍数関係の総数は

∑x=1N⌊Nx⌋\sum_{x=1}^{N}\left\lfloor\frac{N}{x}\right\rfloor

です。

これは調和級数の形であるため、DPの遷移の数は O(Nlog⁡N)O(N\log N) となります。

各遷移で 6464 個の XOR 値を調べ、各クエリでも 6464 個の値を調べるため、全体の時間計算量はAiA_i が取りうる値の種類数 σ=64\sigma = 64 として O(σ(Nlog⁡N+Q)) O(\sigma(N\log N+Q)) です。

ユーザー解説

ユーザー解説を書く

ユーザー解説はまだありません。