Good Bye 2020 E. Apollo versus Pan
まず、
- シグマをみたら式変形
- ビット演算は桁ごとに見る
のが基本なのでやってみる
はに依存しないのでシグマの外に出す
との両者がに依存するので、シグマの順番を入れ替える
これはプログラムで書くと、
let mut ans = 0; for i in 0..N { let mut x = 0; let mut y = 0; for j in 0..N { x += a[i] & a[j]; y += a[i] | a[j]; } ans += x * y; }
となる
このままではとなり間に合わないので、forの中のビット演算を桁ごとにみることで計算量を減らしたい。
この式(プログラム)を解釈すると、を順番にみていって、各にたいして、からまでとANDとORをとって足したものを掛け合わせたものを、足していっている。
つまり、をみたときに、からまでとAND(OR)をとった和が高速に求まれば良い。
これはよくある設定で、
2進数で各桁でみていってとき、のd桁目が「1」なら、からでの各数のd桁目が「1」なら「AND」をとった結果は「1」となり、「0」なら「AND」をとった結果は「0」となる。
同様にのd桁目が「1」なら、からでの各数のd桁目が「1」「0」どちらであれ「OR」とった結果は1になる。のd桁目が「0」なら、からでの各数のd桁目が「1」なら「1」、「0」なら「0」となる。
d桁目が「1」になる場合がいくつあるのかがわかれば、それらの和はいくあるかで求めることが出来る。 (2進数でd桁目は)
つまり、からまでの各数にたいして、d桁目が「1」がいくつあるかの分布がわかれば高速に求めることが出来る。
modを自分で毎回とるとバグりがち&「1 << d」とかを32bitで処理しないように注意。
この方法でAC。