【D题】【位运算】 Codeforces Round #628 (Div. 2)

在这里插入图片描述
题意:
给定两个数,u,v;
要求你输出一个最短的数组,
先输出数组的长度,再输出各个元素。
这个数组要求所有元素异或和为u,
所有元素数字之和为v
比如:
a⊕b⊕c=u , a+b+c=v;

比赛思路:
能有什么思路? 我就满脸懵逼啊
一直看着题目,希望可以从中看出一些端倪;
结果还是不知道 到底应该如何入手这题,我寻思也没有什么用法可以完成这个重任啊。。。

题解:

#include <stdio.h>
 
int main() {
	long long u, v, w;
 
	scanf("%lld%lld", &u, &v);
	if (u > v || (v - u) % 2 != 0) {
		printf("-1\n");
		return 0;
	}
	if (u == 0 && v == 0) {
		printf("0\n");
		return 0;
	}
	if (u == v) {
		printf("1\n");
		printf("%lld\n", u);
		return 0;
	}
	w = (v - u) / 2;
	if ((u & w) == 0) {
		printf("2\n");
		printf("%lld %lld\n", w, u ^ w);
		return 0;
	}
	printf("3\n");
	printf("%lld %lld %lld\n", u, w, w);
	return 0;
}

搬了榜最前的一个大佬的代码,
写得很清晰;也感谢群里大佬的解答

解题思路:


要注意好细节,
这给的u,v首先就很大 先开longlong
然后就是分类挺多的,要考虑周全,不然就要wa个好几次

二,
要知道这么一个概念
一个数异或两次另一个数,结果还是等于自身;
换成公式来说就是 u = u ⊕ t ⊕ t;
ps:这个是可以推出来的,但是要记住比较好。
由此我们就只要 让 v = u + t + t
这样的话,题目的两个条件就都满足啦。

三,
但是如何让这个数组的长度更短呢?
这里还要知道一个概念,
两个数,比如数a,b。
如果他们的每一位都不同时为1的话,
那么这两个数 a + b = a ⊕ b;

这也是可以推理得出来的,
0⊕1=1 , 1⊕0=1 , 0⊕0=0 这三个异或的结果都是与加法的结果一样的,当然如果是1⊕1的话 虽然 无论是异或 还是 加法 都是变成0,但是加法里还要进位,所以当有一位同时为 1 时,a + b = a ⊕ b就不满足了。
知道了这个概念以后,我们就可以把数组缩短成 u+tt 这两个元素了。
只要加一层判断,判断是否 u&w==0,如果有某位同时为1的话,那肯定就不为0,就不走这层过了。
所以只要满足u & w == 0,那么直接输出2,以及这两个元素

四,
我们还要注意什么?
① 如果给的 u , v
1)u>v时,那肯定找不到这样的数组,输出-1;
2)u,v的奇偶不同的话,也要输出-1;为何?
因为首先 t+t 之和肯定是偶,那如果u为奇,则v肯定为奇;
如果u为偶,那v也肯定为偶;
所以当u,v奇偶不同时,肯定找不到符合的数组,直接输出-1
② 如果u和v同时为0的话,直接输出0
③ 如果u和v同时为1的话,输出1,输出u或v

感觉这几个坑点蛮恶心的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值