Ehab the Xorcist (异或性质,构造)
题面翻译
给定整数 u u u 和 v ( 0 ≤ u , v ≤ 1 0 18 ) v(0\le u,v \le 10^{18}) v(0≤u,v≤1018),试构造长度最短的数组,使得数组内所有元素的异或和为 u u u,加和为 v v v。
如果有解,输出两行,第一行输出一个整数 n n n,第二行输出 n n n 个非负整数,表示数组里的元素。多解输出任意一组即可。如果无解,输出一行一个整数 − 1 -1 −1。
输出格式
If there’s no array that satisfies the condition, print “-1”. Otherwise:
The first line should contain one integer, $ n $ , representing the length of the desired array. The next line should contain $ n $ positive integers, the array itself. If there are multiple possible answers, print any.
样例 #1
样例输入 #1
2 4
样例输出 #1
2
3 1
样例 #2
样例输入 #2
1 3
样例输出 #2
3
1 1 1
样例 #3
样例输入 #3
8 5
样例输出 #3
-1
样例 #4
样例输入 #4
0 0
样例输出 #4
0
提示
In the first sample, $ 3\oplus 1 = 2 $ and $ 3 + 1 = 4 $ . There is no valid array of smaller length.
Notice that in the fourth sample the array is empty.
注意到一些性质:
- a + b ≥ a ⨁ b a+b \ge a \bigoplus b a+b≥a⨁b
- 对于同一组数,对他们求和 与 对他们求异或和,奇偶性不变。
- a + b = a ⨁ b + 2 ∗ ( a & b ) a+b = a \bigoplus b + 2*(a\&b) a+b=a⨁b+2∗(a&b)
思维过程:
根据异或是不进位加法,性质1易得;
分析样例,观察奇偶性,或者之前就知道性质2,性质2也有了。
特判掉长度是1的情况。
现在,数组长度至少是2,且 u<v,u与v同奇偶。
如果之前做过异或的构造题,应该对性质3有印象,如果忘记了系数,可以确定一下;
void solve(){
srand((unsigned)time(NULL));
int A,B,a,b;
a = rand();
b = rand();
debug(a);
debug(b);
for(A = -10000;A<=10000;A++){
for(B = -10000;B<=10000;B++){
if((a+b) == A*(a^b) + B*(a&b)){
cout<<"!"<<endl;
cout<<A<<" "<<B<<endl;
}
if((a^b) == A*(a+b) + B*(a&b)){
cout<<"!!"<<endl;
cout<<A<<" "<<B<<endl;
}
if((a&b) == A*(a+b) + B*(a&b)){
cout<<"!!!"<<endl;
cout<<A<<" "<<B<<endl;
}
}
}
}
得到 a + b = a ⨁ b + 2 ∗ ( a & b ) a+b = a \bigoplus b + 2*(a\&b) a+b=a⨁b+2∗(a&b) ,并且发现 a & b a\&b a&b 可能得 0 0 0 。
现在就到了创造或是说经验的时候了
令 x = ( a + b − a ⨁ b ) / 2 x = (a+b - a\bigoplus b) /2 x=(a+b−a⨁b)/2 , [ x , x , u ] [x,x,u] [x,x,u] 是一种构造方案。也就是说最大长度为 3 3 3 ;
那么考虑 [ u , x + u ] [u,x+u] [u,x+u] 是否合法?如果合法,那么长度可以变成 2 2 2 ;
需要满足 u ⨁ ( x + u ) = x u \bigoplus (x+u) = x u⨁(x+u)=x ,即 u ⨁ x = u + x u \bigoplus x = u+x u⨁x=u+x , 根据性质3,需要满足 u & x = = 0 u\&x==0 u&x==0 ;
所以,当 u & x = = 0 u \& x == 0 u&x==0 时,使用 [ u , x + u ] [u,x+u] [u,x+u] ;
否则,使用 [ u , x , x ] [u,x,x] [u,x,x] 。
ll u,v;
void solve(){
cin>>u>>v;
if((u&1) != (v&1) || u>v){
puts("-1");
}
else if(u==v){
if(u==0){
puts("0");
}
else{
cout<<1<<endl<<u<<endl;
}
}
else{ // u<v
ll x = (v-u)/2;
// debug(x);
if((x&u)!=0){
puts("3");
cout<<u<<" "<<x<<" "<<x<<endl;
}
else{
puts("2");
cout<<x+u<<" "<<x<<endl;
}
}
}