정수 A와 B가 주어지면 정수 X를 찾으면 다음과 같습니다.
- A, B <2 * 1e18
- A xor X = B + X
나는 수학을 사용하여이 방정식을 풀 수 있다는 것이 의심 스럽다. 이것은 3 년 전에 발생한 코딩 문제이며 지금까지도 스스로 해결할 수 없습니다.
지금까지 내 코드 : (이것은 무차별 대입 솔루션입니다)
#include <iostream>
using namespace std;
int main()
{
unsigned long long a, b;
cin >> a >> b;
for (unsigned long long x = 1; x < max(a, b); x++) {
unsigned long long c = a ^ x;
unsigned long long d = b + x;
if (c == d) {
cout << x << endl;
break;
return 0;
}
}
cout << -1; //if no such integer exists
return 0;
}
답변
참고하십시오 A + X == (A xor X) + ((A and X)<<1)
. 그래서:
A xor X = A + X - ((A and X)<<1) = B + X
A - B = (A and X)<<1
그리고 우리는 :
(A - B) and not (A<<1) = 0 (All bits in (A - B) are also set in (A<<1))
(A - B)>>1 = A and X
조건이 충족되면 A에 설정된 비트가없는 정수 Y의 경우 (((A-B) >> 1) 또는 Y)가 해입니다. 하나의 솔루션 만 원하면 Y = 0 인 ((A-B) >> 1)을 사용할 수 있습니다. 그렇지 않으면 솔루션이 없습니다.
int solve(int a, int b){
int x = (a - b) >> 1;
if ((a ^ x) == b + x)
return x;
else
return ERROR;
}
답변
우리가 작성하는 가정 : 그것은 당신이 단지 작은 생각해야, 매우 어렵지 않습니다 A
, B
그리고 X
바이너리와 Aᵢ
맨 오른쪽 2에 해당하는 값이다 ⁱ 비트.
우리는 그것을 알고 있습니다 : Aₒ ⊕ Xₒ = Bₒ + Xₒ
.
A = 15 및 B = 6을 평가하는 방법을 발견하는 예제를 사용하십시오. 이진으로 변환 :
A = 1 1 1 1 B = 0 1 1 0
X = a b c d X = a b c d
이제 몇 가지 가능성이 있습니다. A와 B의 가장 오른쪽 비트를 분석해 봅시다 :
1 ⊕ d = 0 + d
우리는 d
0 또는 1 만 될 수 있다는 것을 알고 있습니다.
for d = 0
1 ⊕ d = 0 + d => 1 ⊕ 0 = 0 + 0 => 1 = 0 (not possible)
for d = 1
1 ⊕ d = 0 + d => 1 ⊕ 1 = 0 + 1 => 0 = 1 (not possible)
XOR은 이진 합계와 동일하게 동작합니다 (XOR이 다음 비트 합계에 대한 이월을 생성하지 않는다는 차이점이 있음).
XOR SUM
0 ⊕ 0 = 0 | 0 + 0 = 0
0 ⊕ 1 = 1 | 0 + 1 = 1
1 ⊕ 0 = 1 | 1 + 0 = 1
1 ⊕ 1 = 0 | 1 + 1 = 0
이 만족하는 X를 찾기 위해 항상 가능하지 않도록 A ⊕ X = B + X
,이 없기 때문에 값을 d
만족 1 + d = 0 + d
.
어쨌든 X가 존재하면 오른쪽에서 왼쪽으로 비트 단위 로이 방법을 찾을 수 있습니다.
작업 전체 예
A = 15, B = 7 :
A = 1 1 1 1 B = 0 1 1 1
X = a b c d X = a b c d
1 ⊕ d = 1 + d
여기에 d = 0과 d = 1이 모두 적용됩니다. 그러면 무엇입니까? 다음 비트를 확인해야합니다. d = 1이라고 가정하십시오.
A = 1 1 1 1 B = 0 1 1 1
X = a b c d X = a b c d
1 ⊕ d = 1 + d => 1 ⊕ 1 = 1 + 1 => 0 = 0 (possible)
BUT 1 + 1 = 0 generates a carryover for the next bit sum:
Instead of 1 ⊕ c = 1 + c, we have 1 ⊕ c = 1 + c (+1) =
1 ⊕ c = c (not possible)
따라서이 경우 d는 0이어야합니다.
carryover 0
A = 1 1 1 1 B = 0 1 1 1
X = a b 0 0 X = a b 0 0
-----------------------------------
0 0
we know that c must be 0:
carryover 0 0
A = 1 1 1 1 B = 0 1 1 1
X = a b 0 0 X = a b 0 0
-----------------------------------
1 1 1 1
그러나 b는 어떻습니까? 우리는 항상 다음 비트를 확인해야합니다.
if b = 0, there won't be a carryover, so we'll have:
1 ⊕ a = 0 + a (and this is not possible)
so we try b = 1:
1 ⊕ b = 1 + b => 1 ⊕ 1 = 1 + 1 => 0 = 0 (with carryover)
그리고 지금 a
:
carryover 1 0 0
A = 1 1 1 1 B = 0 1 1 1
X = a 1 0 0 X = a 1 0 0
-----------------------------------
0 0 0 0 0 0
1 ⊕ a = 0 + a (+1) => 1 ⊕ a = 1 + a
여기에서 a
0과 1이 될 수 있지만 합계에서 이월을 피하려면 0이어야합니다 B + X
.
그런 다음 X = 0 1 0 0
X = 4입니다.
암호
#include <iostream>
using namespace std;
inline int bit(int a, int n) {
if(n > 31) return 0;
return (a & ( 1 << n )) >> n;
}
int main(){
int A = 19;
int B = 7;
int X = 0;
int carryover = 0;
int aCurrent, aNext, bCurrent, bNext;
for(int i = 0; i < 32; i++){
aCurrent = bit(A, i); bCurrent = bit(B, i);
aNext = bit(A, i + 1); bNext = bit(B, i + 1);
if(aCurrent == 0 && bCurrent == 0){
if(carryover) {X = -1; break;}
if(aNext != bNext){
X += 1 << i;
}
carryover = 0;
}
else if(aCurrent == 0 && bCurrent == 1){
if(!carryover) {X = -1; break;}
if(aNext == bNext){
X += 1 << i;
}
carryover = 1;
}
else if(aCurrent == 1 && bCurrent == 0){
if(!carryover) {X = -1; break;}
if(aNext != bNext){
X += 1 << i;
carryover = 1;
}
else {
carryover = 0;
}
}
else if(aCurrent == 1 && bCurrent == 1){
if(carryover) {X = -1; break;}
if(aNext != bNext){
X += 1 << i;
carryover = 1;
}
else {
carryover = 0;
}
}
}
if(X != -1) cout<<"X = "<<X<<endl;
else cout<<"X doesnt exist"<<endl;
return 0;
}
여기서 테스트 할 수 있습니다 .