codeforces 1325D 位运算+思维
ok
题意:给了两个数u,v(1e18),输出一个长度为n的数组,使得该数组异或等于u,相加等于v。
思路: 当v大于u的时候无结果,v=u的时候分情况,如果u=0,输出0,否则输出1和u。
根据异或的规律,我们可以先让u和0异或成为u,则满足了第一个条件,如果还想满足第二个条件,则要根据v-u的值来处理。把v-u平均分在u和0的二进制同时为0的位置上,即使得u+a 等于0+a,使得(u+a)^(0+a)等于u,且u+a+0+a即u+2a为v,但是v-u不一定能为偶数,如果为奇数,经验证,是不可能有解的,所以v-u为奇数的时候输出-1。
如何把(v-u)/2 = a平均分到u和0上使得(u+a)^(0+a)等于u呢,u的二进制有1有0,0的二进制只有0,只需要把a的二进制求出来,如果a的二进制和u的二进制没有存在同一位置都为1的情况(如果都为1,异或为0,但是0的二进制为0,加上了a则为1,加上了之后(u+a)^(0+a)遍不再等于u了),直接输出2,a,v-a。如果存在都为1,则输出3,u,a,a即为最优解。
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <string> #include <map> #include <iomanip> #include <algorithm> #include <queue> #include <stack> #include <set> #include <vector> //const int maxn = 1e5+5; #define ll long long #define inf 0x3f3f3f3f #define FOR(i,a,b) for( int i = a;i <= b;++i) #define bug cout<<"--------------"<<endl ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} ll lcm(ll a,ll b){return a/gcd(a,b)*b;} using namespace std; int a[1000000],b[1000000]; int main() { ll u,v; cin>>u>>v; ll tmp = (v - u)/2; int t1 = 0,t2 = 0; ll temp = u; while(temp) { a[++t1] = temp%2; temp /= 2; } /* for(int i = 1;i <= t1; ++i) { cout<<a[i]<<" "; }*/ if((v-u) % 2 == 1 || (v-u) < 0) { cout<<-1<<endl; } else if(v-u == 0) { if(u == 0) cout<<0<<endl; else { cout<<1<<endl; cout<<u<<endl; } } else { ll hhh = tmp; while(hhh) { b[++t2] = hhh%2; hhh /= 2; } int flag = 0; for(int i = 1;i <= t1; ++i) { if(a[i] == b[i] && a[i] == 1) { flag = 1; break; } } if(flag == 0) { /* ll ans = 1; ll maxx = max(t1,t2); for(int i = maxx;i >= 1; --i) { b[i] += a[i]; if(b[i] == 0) { ans *= 2; } else if(b[i] == 1) { ans = ans * 2 + 1; } }*/ ll ans = v-tmp; cout<<2<<endl; cout<<ans<<" "<<tmp<<endl; } else if(flag == 1) { cout<<3<<endl; cout<<u<<" "<<tmp<<" "<<tmp<<endl; } } }