Ex - Multiply or Divide by 2 Editorial by w2w2


問題文の操作は、\(x \in A\) をそれぞれ右シフト/左シフトすることに対応します。

ここで、にわかに \(x \in A \cup B\)\(\mathrm{popcount}(x)\) が最大なものをとってきて、\(\mathrm{trailing\_zeros}\) の差を無視したうえで \(x\) と一致するような \(y \in A\) の多重集合 \(S_A\)\(z \in B\) の多重集合 \(S_B\)を考えます。

このとき、\(S_B\) の元は \(S_A\) の元以外から操作によって得られないことがわかります。また、 \(S_A\) の元を操作によって \(S_B\) の元以外に一致させるとしたら、\(\mathrm{trailing\_zeros}\) の形を変える必要があるため、\(\mathrm{trailing\_zeros} + 1\) 回の右シフトが必要になります。

以上から、もし操作列で \(A\)\(B\) を一致させるものが存在するならば、「\(S_A\) の一部に操作して \(S_B\) と一致するようにし、余りは \(\mathrm{trailing\_zeros} + 1\) 回右シフトする」ことを最初にする操作回数最小で \(A\)\(B\) を一致させる操作列は存在します。「」内を実現する操作はその操作列によらず同じ結果をもたらすので、単に操作回数が最小のものをとればよいです。

この操作回数を最小にする操作列の一つとして \(S_A, S_B\) を降順にソートして、前から \(S_A\) の元を対応する \(S_B\) の元と一致させ、対応する \(S_B\) の元がなくなった \(S_A\) の元を \(\mathrm{trailing\_zeros} + 1\) 回右シフトするものをとれることがわかります。そのようなものが存在しないとき、\(-1\) を出力します。一致した \(S_A\)\(S_B\) は取り除いてよいです。

以上に述べた操作で \(\mathrm{popcount}(x)\) が最大なものの数が減っているので、操作は停止し、最適な操作列を与えます。
計算量は、ソートを \(\mathrm{prioriry\_queue}\) で行うとすると、各数は \(O(\log x)\)\(\mathrm{priority\_queue}\) に挿入されるため、どの \(\mathrm{priority\_queue}\) に挿入するかを決める際に \(\mathrm{map}\) を用いると、\(O(N\log ( N\max(A \cup B)) \log N \log \max(A \cup B))\) となります。

実は \(\mathrm{popcount}(x)\) が最大なものをとってくる必要はなく、\(S_B\)\(S_A\) 以外から得られなければよいので、\(\mathrm{trailing\_zeros} \) を除いたうえで一番大きいものをとってもいいです。

実装例 https://atcoder.jp/contests/abc254/submissions/32262305

posted:
last update: