解説
この解説では、 自身を除く の約数を の 真の約数、 自身を除く の倍数を の 真の倍数 と呼びます。
各クエリについて から までの移動方法をすべて調べるのは困難です。そこで、すべての について、 から まで移動したときに実現できる XOR の値をあらかじめ求めます。
移動を逆向きに考える
問題では、現在いる整数を とすると、 の真の約数 へ移動できます。すなわち、
という移動が可能です。
これを逆向きに見ると、 と移動できるのは、 が の真の倍数であるときです。したがって、整数 から移動できる整数は
です。
また、XOR は計算する順番を入れ替えても値が変わりません。したがって、
という経路を逆向きにした
を考えても、経路上の の XOR は同じです。
よって、整数 から各整数 へ向かう方向に DP を行います。
DP の定義
を、
から まで真の倍数へ移動する経路のうち、経路上の整数に書かれた値の XOR を にできるものが存在するか
を表す bool 値とします。
であるため、いくつ XOR を取っても値は 以上 以下です。したがって、各 について考える必要がある は 通りだけです。
DP の初期値
のとき、通っている整数は だけなので、
とします。それ以外の状態はすべて false で初期化します。
DP の遷移
整数 について、
であるとします。
の真の倍数 へ移動すると、新たに整数 を通るため、XOR に が追加されます。したがって、
と遷移できます。
の真の倍数は なので、実装では次のように列挙できます。
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;
}
}
}
}
常に が成り立つため、 の小さい順に処理すれば、遷移元の状態はすでに確定しています。
クエリへの回答
クエリ を考えます。
である は、 から まで移動したときに実現できる XOR の値です。この経路を選んだときのスコアは
です。
したがって、答えは
です。
は 以上 以下なので、各クエリについて 通りすべてを試せばよいです。
計算量
整数 からは、その真の倍数 へ遷移します。
したがって、倍数関係の総数は
です。
これは調和級数の形であるため、DPの遷移の数は となります。
各遷移で 個の XOR 値を調べ、各クエリでも 個の値を調べるため、全体の時間計算量は が取りうる値の種類数 として です。
ユーザー解説
ユーザー解説を書くユーザー解説はまだありません。