CF-Round#628-div2-D题
D. Ehab the Xorcist
本题异或构造题。
看到异或我真的怕。。。
这里表示一下加法转化为异或的公式:
a+b=a⊕b+2∗(a&b)
异或其实是不进位的加法。
题目要求让你构造一个序列。让这些序列的和为v,然后异或的值为u。构造的序列长度尽可能小。
我们讨论几种特殊情况。
当u>v的时候不存在这样的序列输出-1
当u=v=0的时候看样例只输出一个0,空序列
当u=v != 0的时候就输出长度为1的u就可以啦
当u<v的时候
我们很容易发现构造的序列长度最小为2,最大为3.
为啥捏,你看。我们直接把u丢进序列中,然后剩余的就是x和x,x = (v-u)/2;
这里还需要再讨论一下,如果v-u不是偶数的话,也输出-1,因为奇数的话加起来就不等于v-u了呀。
所以长度为3的序列[u, x, x]是一定满足要求的。
但是题目要求是求最小的长度。
我们考虑一下长度三能否转换为长度为2
根据这个式子a+b=a⊕b+2∗(a&b)=v
我们可以得到:
a &b=(v−u)/ 2=x
如果x中的某一位为1。那么a和b的那一位必然都为1.因为相与嘛
所以a⊕b=u.所以u的那一位必然为0
如果x和u的同一位均为1.那么就不能满足x&u=0 。那么我们找不到这样的a,b所以一定序列的长度一定为3
如果x中的某一位为0,那么a和b没有特殊要求
如果x &u=0。这就意味着我们带入上面的式子a+b=a⊕b+2∗(a&b):
得到异或其实就是加法x⊕u=x+u;
所以我们可以得到序列长度为2的序列:[x+u, x]
好啦解释完啦~
代码部分:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll u, v;
ll x;
int main()
{
cin >> u >> v;
if (u > v)
{
cout << "-1\n";
}
else if (u == v)
{
if (!v)
{
cout << 0 << endl;
}
else
{
cout << 1 << endl << v;
}
}
else
{
if ((v - u) & 1)
{
cout << "-1\n";
}
else
{
x = (v - u) / 2;
if (!(u & x))
{
cout << "2\n";
cout << x + u << " " << x << endl;
}
else
{
cout << "3\n";
cout << u << " " << x << " " << x << endl;
}
}
}
return 0;
}