ARC066-D:Xor Sum

ある意味有名な(?)問題。解説と少し違ったので思うので書いてみる。

問題

atcoder.jp

考察

 とりあえず、xorと和の関係を表す式であるところの a + b = a \ \mathrm {xor} \ b + 2 (a\ \mathrm{and} \ b) \cdots (*)を書いてみる。この式は、2つの自然数の足し算というのは、桁ごとの和(xor)と繰上がりに分解できるということを言っている。この式から a + b \geq a\ \mathrm{xor} \ bがわかり、つまり問題文でいうところの v \geq uがわかる。つまり、 v \leq Nということだけ考えれば、N以下ということは自動的に満たされる。
 v \leq Nを固定したときに、条件を満たすuの数を数えたい。当然vをすべて試すわけにはいかないので、うまい方法を考える。(*)式を見ると、v  = (a+b) a\ \mathrm{and}\ bの値を決めれば、u (= a\ \mathrm{xor}\ b)の値も決まることがわかる。そこで、vの値を決めたときに、 a \ \mathrm{and}\ bとしてあり得るものを数えることを考えてみる。これはvの2進数表記の各桁が、0か1かを決めながら数えられそうである。そこで、vの上位の桁から決めていく桁dpを考えることにする。ところが、上から決めるにあたって、vの各桁の値を決めていくだけでは正しく数えることができない。それは、足し算に繰り上がりがあるからである。そこで、今の桁は下の桁からの繰上あがりを考慮するか?という情報を持つことにする。dp定義をまとめれば

  • dp _ {i,j,k} : a + bの値を上からi桁目まで決めたときのa\ \mathrm{and}\ bの通り数。ここで、ja+b \lt Nが確定しているかどうかのフラグ、ki-1桁目からの繰り上がりを考慮しているかどうかのフラグ。

dpの遷移は難しくない(実装参照)。例えばa+bの上からi+1桁目を1にするときを考える。a\ \mathrm{and} \ bを1にしたい場合、上からi桁目に繰り上がりが生じるので、dp _ {i,j,1}からの遷移が行われることになる。a\ \mathrm{and} \ bを0にしたい場合、上からi+1桁目への繰り上がりを考慮するかどうかで、遷移を場合分けすることになる。答えはNが2進数表記でn桁であったとして、dp _ {n,0,0} + dp _ {n,1,0}となる。

実装

atcoder.jp

この解法は思いつきやすいと思う。