Codeforces 388(#228 Div1) D. Fox and Perfect Sets

問題

集合Sがperfectであるとは、任意の(同一でもよい)a, b∈Sについて、
(a xor b)∈Sとなることを言うものとする。


全ての要素がk以下であるようなSの選び方は何通りあるか、
mod 10^9 + 7で求めよ。

制約条件

k≦10^9

方針

editorialみた。


Sに要素を追加していくことを考えるとき、
今までのSの要素のどれでもないものをc入れれば、
a, b∈Sでa xor c = bとなるものは絶対にない。あったらa xor b = cとなってしまうから。


この新たに追加する要素というのはSの基底であると考えることができる。
ので、一つのSには一つの線形空間が一対一で対応していると言える。


Sに(上位ビットから順に考えて)基底を追加していくことを考える。
今までj本の基底を入れたとする。
i番目のビットを最上位ビットとする基底を入れるとき、
その基底のi番目のビットは1で、ほかの基底のi番目のビットは0にする。
基底を入れないとき、他の基底のi番目のビットは自由に選んでよいので2^j通り。


基底を決めたときにできる最大のベクトルを求めるのは簡単で、
i番目のビットが最上位ビットである基底があったらそのビットは1
なかったら、2^j / 2通りがそのビットを1にする基底で、2^j / 2通りがそのビットを0にする基底。


以上を元に桁DPをすればいい。
j = 0の場合だけは例外で、そのビットを1にする基底は存在しない。

ソースコード

const int mod = (int)1e9 + 7;
ll k, dp[40][40][2];

int main(){
	cin >> k;
	dp[39][0][0] = 1;
	
	for(int i = 38; i >= 0; i--) rep(j, 40) rep(s, 2){
		
		ll cur = dp[i + 1][j][s];
		if(!cur) continue;
		
		if(s || (k >> i & 1)) (dp[i][j + 1][s] += cur) %= mod;
		if(j == 0){
			dp[i][j][s || (k >> i & 1)] += cur;
			dp[i][j][s || (k >> i & 1)] %= mod;
			continue;
		}
		rep(l, 2){
			if(!s && (k >> i & 1) < l) continue;
			int ns = s || (k >> i & 1) > l;
			dp[i][j][ns] += cur * (1 << j - 1) % mod;
			dp[i][j][ns] %= mod;
		}
	}
	ll ans = 0;
	rep(i, 40) ans += dp[0][i][0] + dp[0][i][1];
	cout << ans % mod << endl;
	return 0;
}