题目给定一个整数 ( x ),要求我们找到最小的正整数 ( y ),使得以下等式成立:
[
(x \mathbin{&} y) + (x \mathbin{|} y) = 2025
]
其中 (&) 表示按位与运算,(|) 表示按位或运算。如果不存在这样的正整数 ( y ),则输出 (-1)。
本题的关键在于下面的恒等式:
对于任意整数 ( a, b ),恒有:
[
a + b = (a \mathbin{&} b) + (a \mathbin{|} b)
]
为什么成立?
我们从二进制加法的角度来理解:
[
a + b = (a \oplus b) + 2 \times (a \mathbin{&} b)
]
而按位或又可以拆分为:
[
a \mathbin{|} b = (a \oplus b) + (a \mathbin{&} b)
]
将两者相加:
[
(a \mathbin{&} b) + (a \mathbin{|} b) = (a \mathbin{&} b) + (a \oplus b) + (a \mathbin{&} b)
= (a \oplus b) + 2 \times (a \mathbin{&} b) = a + b
]
所以恒等式成立。
利用该恒等式,原条件等价于:
[
x + y = 2025
]
也就是说,只需要找到一个正整数 ( y ),使得它与 ( x ) 的和等于 2025 即可。显然:
[
y = 2025 - x
]
由于题目要求 ( y ) 为正整数,所以:
参考代码使用了从 1 到 2025 的循环枚举 ( i ),并检查是否满足原始等式。
由于恒等式的存在,第一次遇到的满足条件的 ( i ) 必然就是 ( 2025 - x ),所以暴力枚举也能得到正确结果,只是时间复杂度为 ( O(2025) )。
在已知恒等式的前提下,解题只需一步:
时间复杂度:( O(1) )。
空间复杂度:( O(1) )。
当然,若采用参考代码的方法,遍历 1 到 2025 也是可行的,因为常量范围极小。
cpp1#include <cstdio> 2using namespace std; 3int x; 4int main() { 5 scanf("%d", &x); 6 for (int i = 1; i <= 2025; i++) // 在 1~2025 范围内寻找 y 7 if ((x & i) + (x | i) == 2025) { // 检查题目给出的条件 8 printf("%d\n", i); 9 return 0; 10 } 11 printf("-1\n"); // 没有找到则输出 -1 12 return 0; 13}
解释:
(x & i) + (x | i),如果等于 2025 则输出并结束程序。cpp1#include <cstdio> 2 3int main() { 4 int x; 5 scanf("%d", &x); 6 int y = 2025 - x; 7 if (y > 0) 8 printf("%d\n", y); 9 else 10 printf("-1\n"); 11 return 0; 12}
解释:
在实际比赛中,两种方法均可在 1ms 内轻松通过,不过后者更优雅高效。
本题考察了对位运算基本性质的理解,特别是恒等式 ( a + b = (a \mathbin{&} b) + (a \mathbin{|} b) )。一旦发现这一规律,题目就由“位运算搜索”转变为“简单四则运算”,大大降低了难度。对于初学者而言,无法立刻看出恒等式时,采用循环暴力枚举也是一种可行的保底策略。