ABC117D - XXOR
問題概要
個の非負整数とが与えられる。
とするとき、でのの最大値を求めよ。
制約
解法
を求めるためにの範囲を全て計算して最も大きくなるものを求めたいが、制約上では TLE になってしまう。そこで、 に入る値を全て調べることなく解にたどり着けるようなアプローチを考える。
を無視して考えてみる
まず、の制限がない場合、が最大になるにはがどのようになっていればいいか考える。の性質上、を 2 進数で表した時の桁目の値は各の桁目の値にしか関係がないので、各桁ごとに独立に考えることができる。
を 2 進数で表した時の桁目(と表記する)がに寄与する値に注目すると、
となる。が 2 進数で 60 桁まで取れるとすると、なので、
あらかじめ各についての桁目が 1 になっている個数をカウントしておけば、X の桁目はがより大きいものを選んでいけばいいのでで解くことができる。
を考慮する
を考えるにあたり、 の各ビット毎に独立で考えることができることが分かったが、今回は厄介なという制約がある。この制約により、あるに対するを自由に決めてよいかどうかが、以外の他のビットをどのように決めたかに依存してしまう。
そこで、他のビットがどうなっている状態なら を自由に決めてよいかを考察してみる。
まず、の桁目()が 0 なら、そのビットを 1 にしたを作った場合、明らかになのでとできない。 一方なら、そのビットを 0 にしたはになるため、とすることができる。
また、のときにとしたとき、その後より下位の桁を全て 1 に変更したとしてもが保たれる。
まとめると、以下のようになる。
このような制約の元でを決めるには、としたときと、となるビットでとして、下位ビット全ておよび上位のとなっているビットを自由に選んだものを検証すればよい。
例として、 としたとき、自由に選んでよいビットを?で表すと
を調べて、が最大になるを選べばよい。
Code
下記が、rust でこの問題を解いた場合のコードです。
fn solve() {
input! {
n: usize,
k: usize,
a: [usize;n]
}
let mut k_bit = vec![0; 60];
for b in 0..60 {
k_bit[b] = k >> b & 1;
}
let mut a_sum_bit = vec![0; 60];
for i in 0..n {
let a_i = a[i];
for b in 0..60 {
a_sum_bit[b] += a_i >> b & 1;
}
}
// まずx=kの場合のf(x)を見る
let mut ans = 0;
for i in 0..60 {
let base = 1 << i;
ans += if k_bit[i] == 1 {
(a.len() - a_sum_bit[i]) * base
} else {
a_sum_bit[i] * base
}
}
for i in 0..60 {
let mut tmp_ans = 0;
// kのi+1ビット目が1なら、そのビットを0にする代わりに下位のビットは全て0か1のより大きい方として良い
if k_bit[i] == 1 {
for j in 0..60 {
let base = 1 << j;
let bit_j_0 = a_sum_bit[j] * base;
let bit_j_1 = (a.len() - a_sum_bit[j]) * base;
if j < i {
tmp_ans += cmp::max(bit_j_0, bit_j_1);
} else if j == i {
tmp_ans += bit_j_0;
} else {
tmp_ans += if k_bit[j] == 0 { bit_j_0 } else { bit_j_1 };
}
}
}
ans = cmp::max(tmp_ans, ans);
}
println!("{}", ans);
}