Ehab the Xorcist (异或性质,构造)

Ehab the Xorcist (异或性质,构造)

题面翻译

给定整数 u u u v ( 0 ≤ u , v ≤ 1 0 18 ) v(0\le u,v \le 10^{18}) v(0u,v1018),试构造长度最短的数组,使得数组内所有元素的异或和为 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.


注意到一些性质:

  1. a + b ≥ a ⨁ b a+b \ge a \bigoplus b a+bab
  2. 对于同一组数,对他们求和 与 对他们求异或和,奇偶性不变。
  3. a + b = a ⨁ b + 2 ∗ ( a & b ) a+b = a \bigoplus b + 2*(a\&b) a+b=ab+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=ab+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+bab)/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 ux=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;
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值