题意

·给定一条边的长度x, 求满足条件的长度y(y < x),使得x, y, x⊕y 构成非退化的三角形的三条边。

分析

·首先对x, y,和x⊕y, 要构成非退化三角形 需要满足 x + y > x⊕y , y + x⊕y > x, x⊕y + x > y;

·我们先看看y + x⊕y > x 的,因为:

·对二进制表示的x,y :

·对应为 x 位为 0 , y 位为 0 时, x⊕y该位也为 0, 大小与x一致

·对应为 x 位为 0 , y 位为 1 时, x⊕y该位为 1, 比x大

·对应为 x 位为 1 , y 位为 0 时, x⊕y该位也为 1,大小与x一致

·对应为 x 位为 1 , y 位为 1 时, x⊕y该位为 0,虽然比x小, 但是最后 + y 可以补回来而且其他位x⊕y绝对不小于x

·所以y + x⊕y > x 成立, 需要有对应为 x 位为 0 , y 位为 1

·又由题目条件 y < x

·所以x⊕y + x > y也必然成立

·这样以来题目就变成了找小于x的y, 同时有对应为 x 位为 0 , y 位为 1 使得 x + y > x⊕y 成立

·我们知道当x 与 y 没有位数都为1时, x + y = x⊕y

·所以当x y 有位数都为1时,则都是一的那一位会变为0, 此时就有 x + y > x⊕y

·所以我们就知道了满足条件的y的条件

·有对应位数x为0而y为1, 且有对应位数 与 x都为1, 且 y < x

算法实现

·结合样例里输出-1的情况,我们可以发现:

·当x 为 2 ^ k - 1 ,即 x二进制为全1时, 我们找不到对应的y对应位数x为0而y为1, 因为此时没有 < x 的数有位数为1, 而对应x的位数为0

·当x 为 2 ^ k , 即 x二进制为单个1后面全0时,我们找不到对应的y有对应位数 与 x都为1, 因为唯一能与x对应位数都为1, 必须包含x那个1的一位, 即一定比x大

所以我们特判这两种情况即可

我们可以发现,全1的情况 + 1 可以转化为1后全0的情况

对1后全0的情况,我们可以使用lowbit, 取x最后一位1对应的数与x是否相等来判断

// lowbit 利用补码特性,不知道且感兴趣可以自行学习,总之 -x = ~x (x的反码,即01都反过来) + 1, 所以 x & -x 即为x从右往左第一个1对应的数

int lowbit(int x)
{
	return x & (-x);
}
bool check(int x)
{
	return x == lowbit(x);
}

·然后构建可行的y,我们知道只要满足对应位数x为0而y为1, 且有对应位数 与 x都为1, 且 y < xy 都是可行的

·所以可以找到x的最后一个0和最后一个1对应位为1其他位为0也是可以是满足条件的y

找最后一个0, 可以用 x反码的lowbit实现

找最后一个1,可以用x的lowbit实现

printf("%d\n", lowbit(~n) + lowbit(n));

这样一来,我们通过lowbit,让成功实现了O(1)的可行判定, 和O(1)的结果计算

·时间复杂度O(T), 空间复杂度O(1);

完整代码

// n 即为 x 习惯了(

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> 

using namespace std;

int n;

int lowbit(int x)
{
	return x & (-x);
}

bool check(int x)
{
	return x == lowbit(x);
}

int main()
{
	int T;
	scanf("%d", &T);
	
	while(T -- )
	{
		scanf("%d", &n);
		if (check(n) || check(n + 1))
		{
			puts("-1");
			continue;
		}
		printf("%d\n", lowbit(~n) + lowbit(n));
	}
	
	return 0;
}

希望对大家有所帮助qwq.