#include <stdio.h>
int main() {
int a, b, cnt = 0; for (a=1; a<50; ++a) { for (b=1; b<50; ++b) { if ((a + b) == (a | b)) { ++cnt; } } } printf("%d\n", cnt); return 0;}// 516 출력코드를 작성하지 않고 푸는 풀이는 다음과 같습니다.
우선 식을 변형하겠습니다. 이진법의 계산과 받아올림의 원리에 따라
a + b = (a ^ b) + (a & b) << 1모든 양수 c에 대해서 c << 1은 c * 2이므로,
a + b = (a ^ b) + (a & b) * 2 = (a ^ b) + (a & b) + (a & b)f(a, b) = (a ^ b) + (a & b)라고 잡고 a, b에 따른 계산을 해 주면
f(a, b) = a | b라는 결론을 간단하게 내릴 수 있으므로,f | 0 | 1
--+---+---
0 | 0 | 1
--+---+---
1 | 1 | 1
주어진 조건문은 a | b == (a | b) + (a & b)가 되므로
그것을 a & b == 0으로 간단하게 바꿀 수 있습니다.
a의 비트가 xyz라고 합시다. 만약 x가 0이라면, b의 x 자리에는 임의의 비트(2가지의 경우)가 올 수 있습니다. 만약 x가 1이라면, b의 x 자리에는 반드시 0 비트(1가지의 경우)가 와야 합니다. 따라서 a가 정해져 있을 때, b가 될 수 있는 개수는 2(a의 0인 비트의 개수)개입니다.
i) 1 ≤ a < 32, 1 ≤ b < 32(XXXXX, a 기준으로 변하는 비트 5개)인 경우에는,
1) 0이 하나도 없음: 5C020 = 1ii) 1 ≤ a < 32, 32 ≤ b < 48(10XXXX, b 기준으로 변하는 비트 4개)인 경우에는,
2) 0이 하나 있음: 5C121 = 10
3) 0이 두 개 있음: 5C222 = 40
4) 0이 세 개 있음: 5C323 = 80
5) 0이 네 개 있음: 5C424 = 80
각각의 경우에서, b ≠ 0이므로 이 경우 31가지를 제외하면
합: 1 + 10 + 40 + 80 + 80 - 31 = 180
1) 0이 하나 있음: 4C021 = 2iii) 1 ≤ a < 32, 48 ≤ b < 50(b 기준)인 경우에는,
2) 0이 두 개 있음: 4C122 = 16
3) 0이 세 개 있음: 4C223 = 48
4) 0이 네 개 있음: 4C324 = 64
4) 0이 다섯 개 있음: 4C425 = 32
각각의 경우에서, b ≠ 0이므로 이 경우 16가지를 제외하면
합: 2 + 16 + 48 + 64 + 32 - 16 = 146
1) b = 48(110000(2)) : 24 - 1 = 15iv) 32 ≤ a < 48인 경우에는 32 ≤ b인 경우가 존재할 수 없으므로, a와 b를 바꾸면 ii)와 같아지고, 순서만 뒤바뀐 것입니다. 따라서 개수는 ii)에서 구했던 그대로 146
2) b = 49(110001(2)) : 23 - 1= 8
각각의 경우에서, b ≠ 0이므로 이 경우 2가지를 제외하면
합: 16 + 8 - 2 = 22
v) 48 ≤ a ≤ 50인 경우에는 32 ≤ b인 경우가 존재할 수 없으므로, a와 b를 바꾸면 iii)와 같아지고, 순서만 뒤바뀐 것입니다. 따라서 개수는 iii)에서 구했던 그대로 22
모두 더하면, 180 + 146 + 22 + 146 + 22 = 516
출제진들은 여러분들이 당연히 프로그래밍할 거라고 생각했습니다.
일단 이렇게도 풀 수 있
고, 불가능한 건 없습니다. 혹시 풀이가 이해 안 되시면 댓글 달아주세요.