解法1
f ( a , b ) f(a,b) f ( a , b ) が最大何回の変形で b = 0 b=0 b = 0 にたどり着くかを考えてみてみましょう。
まず、
a 0 = a , b 0 = b a_0=a,b_0=b a 0 = a , b 0 = b
a n = a n − 1 xor b n − 1 a_n=a_{n-1}\ \text{xor}\ b_{n-1} a n = a n − 1 xor b n − 1
b n = 2 × ( a n − 1 and b n − 1 ) b_n=2\times(a_{n-1}\ \text{and}\ b_{n-1}) b n = 2 × ( a n − 1 and b n − 1 )
とします。
ここで、ある非負整数 x x x を 2 2 2 進数表記した時に立っているビットの数を popcount ( x ) \text{popcount}(x) popcount ( x ) とします。
xor , and \text{xor},\text{and} xor , and の性質から、xor \text{xor} xor で打ち消し合ったビットが and \text{and} and に立つので、
popcount ( a n ) + popcount ( b n ) = popcount ( a n + 1 ) + 2 × popcount ( b n + 1 ) ≥ popcount ( a n + 1 ) + popcount ( b n + 1 ) \begin{aligned}
\text{popcount}(a_n)+\text{popcount}(b_n)&=\text{popcount}(a_{n+1})+2\times\text{popcount}(b_{n+1})\\
&\ge\text{popcount}(a_{n+1})+\text{popcount}(b_{n+1})
\end{aligned}
popcount ( a n ) + popcount ( b n ) = popcount ( a n + 1 ) + 2 × popcount ( b n + 1 ) ≥ popcount ( a n + 1 ) + popcount ( b n + 1 )
であることがすぐに分かります。
ここで、等号が成り立つのは b n + 1 = 0 b_{n+1}=0 b n + 1 = 0 の時のみであり、追加で 1 1 1 回変形を行うと、 f ( a , b ) = f ( a n + 1 , 0 ) = a n + 1 f(a,b)=f(a_{n+1},0)=a_{n+1} f ( a , b ) = f ( a n + 1 , 0 ) = a n + 1 を導くことができます。
あとは b n + 1 ≠ 0 b_{n+1}\ne0 b n + 1 = 0 の場合について何回の変形で計算が終了するかが分かればよく、
popcount ( a n ) + popcount ( b n ) > popcount ( a n + 1 ) + popcount ( b n + 1 ) \text{popcount}(a_n)+\text{popcount}(b_n)
>\text{popcount}(a_{n+1})+\text{popcount}(b_{n+1})
popcount ( a n ) + popcount ( b n ) > popcount ( a n + 1 ) + popcount ( b n + 1 )
より、最大で popcount ( a ) + popcount ( b ) \text{popcount}(a)+\text{popcount}(b) popcount ( a ) + popcount ( b ) 回程度の変換で b n = 0 b_n=0 b n = 0 にたどり着くことが分かります。
以上より、O ( log a + log b ) O(\log a+\log b) O ( log a + log b ) 回の変換で b = 0 b=0 b = 0 になることが分かりました。
再帰関数等を用いて問題文の f ( a , b ) f(a,b) f ( a , b ) をそのまま愚直に実装します。
計算量は O ( N log ( X + ∑ A ) ) O(N\log(X+\sum A)) O ( N log ( X + ∑ A )) です。
解法2
実は、2 2 2 進数の足し算の筆算を考えることで、f ( a , b ) = a + b f(a,b)=a+b f ( a , b ) = a + b が分かります。
より厳密には、以下の議論によって f ( a , b ) = a + b f(a,b)=a+b f ( a , b ) = a + b を証明することができます。
f ( x , i ) f(x,i) f ( x , i ) を非負整数 x x x を 2 2 2 進数表記したときの i i i 桁目とします。
x = ∑ i = N ∞ f ( x , i ) 2 i x=\sum_{i=N}^\infty f(x,i)2^i
x = i = N ∑ ∞ f ( x , i ) 2 i
より、xor , and \text{xor},\text{and} xor , and はビットごとに独立であることから、
a xor b = ( ∑ i = N ∞ f ( a , i ) 2 i ) xor ( ∑ i = N ∞ f ( b , i ) 2 i ) = ∑ i = N ∞ ( f ( a , i ) xor f ( b , i ) ) 2 i a and b = ( ∑ i = N ∞ f ( a , i ) 2 i ) and ( ∑ i = N ∞ f ( b , i ) 2 i ) = ∑ i = N ∞ ( f ( a , i ) and f ( b , i ) ) 2 i \begin{aligned}
a\text{ xor }b&=\left(\sum_{i=N}^\infty f(a,i)2^i\right)\text{ xor }\left(\sum_{i=N}^\infty f(b,i)2^i\right)\\
&=\sum_{i=N}^\infty(f(a,i)\text{ xor }f(b,i))2^i\\
a\text{ and }b&=\left(\sum_{i=N}^\infty f(a,i)2^i\right)\text{ and }\left(\sum_{i=N}^\infty f(b,i)2^i\right)\\
&=\sum_{i=N}^\infty(f(a,i)\text{ and }f(b,i))2^i
\end{aligned}
a xor b a and b = ( i = N ∑ ∞ f ( a , i ) 2 i ) xor ( i = N ∑ ∞ f ( b , i ) 2 i ) = i = N ∑ ∞ ( f ( a , i ) xor f ( b , i )) 2 i = ( i = N ∑ ∞ f ( a , i ) 2 i ) and ( i = N ∑ ∞ f ( b , i ) 2 i ) = i = N ∑ ∞ ( f ( a , i ) and f ( b , i )) 2 i
が成り立ちます。
そして、x , y ∈ { 0 , 1 } x,y\in\{0,1\} x , y ∈ { 0 , 1 } に対して x + y = x xor y + 2 × ( x and y ) x+y=x\text{ xor }y+2\times(x\text{ and }y) x + y = x xor y + 2 × ( x and y ) であることは少し考えればわかるので、上の式と併せて以下が成り立つことが分かります。
a xor b + 2 × ( a and b ) = ∑ i = N ∞ ( f ( a , i ) xor f ( b , i ) ) 2 i + 2 × ∑ i = N ∞ ( f ( a , i ) and f ( b , i ) ) 2 i = ∑ i = N ∞ ( f ( a , i ) xor f ( b , i ) + 2 × ( f ( a , i ) and f ( b , i ) ) ) 2 i = ∑ i = N ∞ ( f ( a , i ) + f ( b , i ) ) 2 i = ∑ i = N ∞ f ( a , i ) 2 i + ∑ i = N ∞ f ( b , i ) 2 i = a + b \begin{aligned}
a\text{ xor }b+2\times(a\text{ and }b)&=\sum_{i=N}^\infty(f(a,i)\text{ xor }f(b,i))2^i+2\times\sum_{i=N}^\infty(f(a,i)\text{ and }f(b,i))2^i\\
&=\sum_{i=N}^\infty(f(a,i)\text{ xor }f(b,i)+2\times(f(a,i)\text{ and }f(b,i)))2^i\\
&=\sum_{i=N}^\infty(f(a,i)+f(b,i))2^i\\
&=\sum_{i=N}^\infty f(a,i)2^i+\sum_{i=N}^\infty f(b,i)2^i\\
&=a+b
\end{aligned}
a xor b + 2 × ( a and b ) = i = N ∑ ∞ ( f ( a , i ) xor f ( b , i )) 2 i + 2 × i = N ∑ ∞ ( f ( a , i ) and f ( b , i )) 2 i = i = N ∑ ∞ ( f ( a , i ) xor f ( b , i ) + 2 × ( f ( a , i ) and f ( b , i ))) 2 i = i = N ∑ ∞ ( f ( a , i ) + f ( b , i )) 2 i = i = N ∑ ∞ f ( a , i ) 2 i + i = N ∑ ∞ f ( b , i ) 2 i = a + b
また、解法1の後半と同様の考察をすることで有限回の変換によって計算結果 a + b a+b a + b が得られることも分かります。
よって、B 1 = X + A 1 B_1=X+A_1 B 1 = X + A 1 に注意して累積和を計算すればよいです。
計算量は O ( N ) O(N) O ( N ) です。
解法1の実装例(C++)
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #include <bits/stdc++.h>
using namespace std;
long long f (long long a, long long b)
{
if (b == 0 ) return a;
return f (a ^ b, 2 * (a & b));
}
int main ()
{
long long N, X, a;
cin >> N >> X;
while (N--)
cin >> a, X = f (X, a), cout << X << " " ;
}
解法2の実装例(C++)
1
2
3
4
5
6
7
8
9 #include <bits/stdc++.h>
using namespace std;
int main ()
{
long long N, X, a;
cin >> N >> X;
while (N--)
cin >> a, X += a, cout << X << " " ;
}