본문 바로가기
Algorithm

[백준] 11723. 집합 / 비트 연산

by Dev_Green 2022. 11. 30.

https://www.acmicpc.net/problem/11723

 

11723번: 집합

첫째 줄에 수행해야 하는 연산의 수 M (1 ≤ M ≤ 3,000,000)이 주어진다. 둘째 줄부터 M개의 줄에 수행해야 하는 연산이 한 줄에 하나씩 주어진다.

www.acmicpc.net

 

풀이

2진수의 각 자리를 1~20까지의 존재 여부를 담는 배열로서 사용한다. 수가 존재하면 1, 그렇지 않으면 0인 것이다.

예를 들어, 집합 S = {1, 3}이라고 한다면 2진수 첫번째 자리와 세번째 자리 숫자는 1이고 나머지 자리는 0일 것이다.

 

  • add x: S에 x를 추가한다. (1 ≤ x ≤ 20) S에 x가 이미 있는 경우에는 연산을 무시한다.
    • s |= (1 << x) : 1을 x만큼 왼쪽으로 쉬프트 연산한 결과를 s와 OR 연산하여 대입한다. 좌항, 우항 중 어느 한 쪽에라도 1이 있으면 1을 결과로 낸다.
  • remove x: S에서 x를 제거한다. (1 ≤ x ≤ 20) S에 x가 없는 경우에는 연산을 무시한다.
    • s &= ~(1 << x) : 1을 x만큼 왼쪽으로 쉬프트 연산한 결과의 부정을 s와 AND 연산하여 대입한다. 좌항, 우항 모두 1이 있어야 1을 결과로 낸다.
  • check x: S에 x가 있으면 1을, 없으면 0을 출력한다. (1 ≤ x ≤ 20)
    • s & (1 << x)) != 0 : 특정 자리 수가 1인 이진수와 s를 AND 연산했을 때 s에도 1이 있어야 1을 결과로 내고, 그렇지 않으면 0을 결과로 낸다.
  • toggle x: S에 x가 있으면 x를 제거하고, 없으면 x를 추가한다. (1 ≤ x ≤ 20)
    • s ^= (1 << x) : 값을 뒤집기 위해 XOR 연산을 한다.
  • all: S를 {1, 2, ..., 20} 으로 바꾼다.
    • s = (1 << 20) - 1 : 이진수의 첫째자리부터 20번째자리까지 모두를 1로 만든다.
  • empty: S를 공집합으로 바꾼다. 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class BOJ11723 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int M = Integer.parseInt(br.readLine());

        int s = 0;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < M; i++) {
            String[] input = br.readLine().split(" ");

            switch (input[0]) {
                case "all":
                    s = (1 << 20) - 1;  // 2진수 첫째자리부터 20번째자리까지 모두 1인 상태
                    break;
                case "empty":
                    s = 0;  // 십진수 0. 곧 이진수로도 모든 자리 숫자 0
                    break;
                // 위 케이스들에 아무것도 해당하지 않을 때 수행될 코드
                default:
                    int x = Integer.parseInt(input[1]) - 1;
                    switch (input[0]) {
                        case "add":
                            s |= (1 << x);  // 좌우 항의 OR 연산 결과를 좌항에 대입
                            break;
                        case "remove":
                            s &= ~(1 << x);  // 좌우 항의 AND 연산 결과를 좌항에 대입
                            break;
                        case "check":
                            sb.append((s & (1 << x)) != 0 ? 1 : 0).append('\n');  // 2진수 상에서 특정 자리 숫자가 1인지 확인
                            break;
                        case "toggle":
                            s ^= (1 << x);  // 좌우 항의 XOR 연산 결과를 좌항에 대입
                            break;
                    }
            }
        }

        System.out.println(sb);
    }
}