コンテスト中に解けなかったけど、解説に載ってた解法以外で解けたのでメモ
D: Xor Sum - AtCoder Regular Contest 066 | AtCoder
この問題は0からvまでの通り数の総和をメモ化したDFSで解けた。
解法
まず、 であることがわかる。
ここで、 とした時に考えられる の値の通り数を とする。
このとき、 なので、 が成り立つ。
また、 である。
の漸化式
ここで、 の時の の値を を0からkまで動かして計算してみる。
n = input() for i in xrange(n+1): r = i^(n-i) print "%3d xor %3d => %3d (= %3d<<1)" % (i, n-i, r, r>>1)
この時、 の値とその値から下位1ビットを除いた値を眺めていると、
という関係が成り立つことに気づく。
例えば、 の時、 の値はが0の時から順番に 6,4,6,0,6,4,6 と出現するが、
の時は 3,3,3,3 、 の時は 2,0,2 と出現しており、 にはそれらを2倍した値が交互に出現してることがわかる。
また、 の時、uの値は 5,5,1,1,5,5 となるが、 の時の 2,0,2 と比較すると、 の場合では の場合の値を2倍して1足した値が2個ずつ出現していることがわかる。
これを一般化して考える。
まず、奇数の場合の を考える。
の時、
と変形でき、
の時、
と変形できる。
この式から、 の場合に出現するuの値を2倍して1足した値が出現することがわかり、 の時に出現するuの値の通り数と の時に出現する値の通り数は同じであることがわかる。
次に、偶数の場合の を考える。
の時、
と変形でき、
の時、
と変形できることがわかる。
この式から、aが偶数の時には の時のuの値を2倍した値、aが奇数の時には の場合のuの値を2倍した値が出現することがわかる。
この時、 の値は、 が奇数の場合はすべて奇数となり、 が偶数の場合はすべて偶数となる。よって、が偶数の場合と奇数の場合では同じ値は出現しないことがわかり、 の時の通り数はそのまま と の通り数の和になることがわかる。
おまけに、この漸化式の数列はこれっぽい。
https://oeis.org/A002487
総和の計算
とする。この時、求めたい値は である。
ここで、について考える。
すると、さっき求めた漸化式を元に以下のように変形できる。
また、 の場合については以下のように変形できる。
そして、 であるため、これで求めたい を計算することができる。
mapなどでメモ化DFSすれば計算量は
こんな感じで書ける。
http://arc066.contest.atcoder.jp/submissions/1033199
N = input() MOD = 10**9+7 memo = {0: 1, 1: 2} def S(k): if k in memo: return memo[k] if k % 2 == 1: result = (2*S(k/2) + S(k/2-1)) % MOD else: result = (S(k/2) + 2*S(k/2-1)) % MOD memo[k] = result return result print S(N)