{ }codelper
참·거짓거듭제곱P0132

권한 비트 검사기

어떤 서비스는 사용자의 권한을 정수 하나(권한 값)에 모아 둔다. 첫 줄에 권한의 수 k가 주어지고, 둘째 줄에 권한 이름 k개가 빈칸 하나씩 띄어 주어진다. 앞에서부터 0번째, 1번째, …, (k-1)번째 권한이라 하고, i번째 권한은 값 2^i에 해당한다. 권한 값을 2진수로 썼을 때 2^i 자리가 1이면 i번째 권한이 있고, 0이면 없다. 예를 들어 권한이 read write delete admin 차례이면 권한 값 5(= 1 + 4)는 read와 delete를 가진다. 셋째 줄에 질문 수 q가 주어지고, 다음 q줄에 질문이 하나씩 주어진다. 질문은 권한 값, 방식, 권한 이름 한 개 이상을 빈칸 하나씩 띄어 쓴 것이다. 방식이 "all"이면 적힌 권한을 모두 가질 때, "any"이면 하나라도 가질 때, "none"이면 하나도 갖지 않을 때 통과다. 질문마다 통과이면 "예", 아니면 "아니요"를 한 줄에 출력하라.

입력
1 ≤ k ≤ 30, 권한 이름은 영어 소문자 1~10글자이고 서로 다름, 1 ≤ q ≤ 1,000, 방식은 all·any·none 중 하나, 0 ≤ 권한 값 < 2^k, 한 질문의 권한 이름은 목록에 있고 서로 다름
출력
질문마다 "예" 또는 "아니요" 한 줄
예시 1 · stdin
4
read write delete admin
5
5 all read delete
5 all read write
2 any read delete
2 any write admin
8 none read write
stdout
예
아니요
아니요
예
예
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

i번째 권한의 값 2^i는 C·C++·Java·C#·JS·TS·Python 모두 비트 밀기 1 << i로 정확히 얻어요.
Python은 2 ** i, Java·C#은 Math.pow/Math.Pow(실수를 돌려줌)로도 되지만, 2의 거듭제곱에는 1 << i가 정수 그대로라 가장 깔끔해요.
2 ^ i는 거듭제곱이 아니라 비트 XOR이라(2 ^ 0 = 2, 2 ^ 1 = 3) 오류 없이 틀린 권한을 봐요.
크레이콘에는 비트 연산도 거듭제곱 연산자도 없어서, 1부터 값 *= 2로 두 배씩 표를 만들고, 수학.몫(mask, 값) % 2 == 1(2^i로 나눈 몫이 홀수)로 그 자리가 켜졌는지 봐요.
연산자 우선순위 함정: C·C++·JS·TS에서 mask & bit != 0은 !=가 먼저라 mask & 1이 되어 엉뚱한 답이 나와요.
꼭 (mask & bit) != 0으로 괄호를 쳐요.
Java·C#에서는 같은 식이 int와 bool을 섞었다고 컴파일 오류가 나서 바로 알 수 있고, Python은 &가 비교보다 먼저라 괄호 없이도 맞아요.
참·거짓 함정: C·C++은 0이 아닌 정수를 참으로 쳐 주지만, Java·C#은 if (mask & bit)를 받지 않고 진짜 boolean이 있어야 해요.
C는 <stdbool.h>의 bool, 크레이콘은 참/거짓이에요.
모두(all)는 참에서 시작해 &&로, 하나라도(any)는 거짓에서 시작해 ||로 모아요.
Python all/any, JS·TS every/some이 같은 일을 해요.
none은 "any가 아님"이지 "all이 아님"이 아니에요.
일부만 가진 사용자에서 둘이 갈라져요.
1 << i는 32비트 int라서 i가 31이면 음수가 되고, Java·C#·JS·TS는 밀 칸 수를 32로 나눈 나머지만 써서 1 << 32가 1이 돼요(C·C++에서는 정의되지 않은 동작).
권한이 32개를 넘으면 64비트 정수(1L << i, 1LL << i, JS·TS는 BigInt)가 필요하지만, 이 문제는 k ≤ 30이라 괜찮아요.

Pythonmain.py · 15 줄
k = int(input())names = input().split()bit_of = {name: 1 << i for i, name in enumerate(names)}  # i번째 권한의 값은 2^iq = int(input())for _ in range(q):    t = input().split()    mask, mode, wanted = int(t[0]), t[1], t[2:]    has = [mask & bit_of[w] != 0 for w in wanted]  # Python은 &가 !=보다 먼저 계산된다    if mode == "all":        ok = all(has)    elif mode == "any":        ok = any(has)    else:  # none        ok = not any(has)    print("예" if ok else "아니요")
JavaScriptmain.js · 16 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const names = lines[1].trim().split(/\s+/);const bitOf = new Map(names.map((name, i) => [name, 1 << i])); // i번째 권한의 값은 2^iconst q = Number(lines[2]);const out = [];for (let j = 0; j < q; j++) {  const [m, mode, ...wanted] = lines[3 + j].trim().split(/\s+/);  const mask = Number(m);  const has = wanted.map((w) => (mask & bitOf.get(w)) !== 0); // 괄호 필수: !==가 &보다 먼저다  let ok;  if (mode === "all") ok = has.every((h) => h);  else if (mode === "any") ok = has.some((h) => h);  else ok = !has.some((h) => h); // none  out.push(ok ? "예" : "아니요");}console.log(out.join("\n"));
TypeScriptmain.ts · 17 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const names: string[] = lines[1].trim().split(/\s+/);const bitOf = new Map<string, number>(names.map((name, i) => [name, 1 << i])); // i번째 권한의 값은 2^iconst q = Number(lines[2]);const out: string[] = [];for (let j = 0; j < q; j++) {  const [m, mode, ...wanted] = lines[3 + j].trim().split(/\s+/);  const mask = Number(m);  const has: boolean[] = wanted.map((w) => (mask & bitOf.get(w)!) !== 0); // 괄호 필수: !==가 &보다 먼저다  let ok: boolean;  if (mode === "all") ok = has.every((h) => h);  else if (mode === "any") ok = has.some((h) => h);  else ok = !has.some((h) => h); // none  out.push(ok ? "예" : "아니요");}console.log(out.join("\n"));
JavaMain.java · 30 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.HashMap;import java.util.Map; public class Main {    public static void main(String[] args) throws Exception {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int k = Integer.parseInt(in.readLine().trim());        String[] names = in.readLine().trim().split("\\s+");        Map<String, Integer> bitOf = new HashMap<>();        for (int i = 0; i < k; i++) bitOf.put(names[i], 1 << i); // i번째 권한의 값은 2^i        int q = Integer.parseInt(in.readLine().trim());        StringBuilder out = new StringBuilder();        for (int j = 0; j < q; j++) {            String[] t = in.readLine().trim().split("\\s+");            int mask = Integer.parseInt(t[0]);            String mode = t[1];            boolean all = true, any = false;            for (int w = 2; w < t.length; w++) {                boolean has = (mask & bitOf.get(t[w])) != 0; // Java는 int를 참·거짓으로 쓸 수 없어 != 0이 꼭 필요하다                all = all && has;                any = any || has;            }            boolean ok = mode.equals("all") ? all : mode.equals("any") ? any : !any;            out.append(ok ? "예" : "아니요").append('\n');        }        System.out.print(out);    }}
C#Main.cs · 32 줄
using System;using System.Collections.Generic;using System.Text; class Program{    static void Main()    {        int k = int.Parse(Console.ReadLine());        string[] names = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        var bitOf = new Dictionary<string, int>();        for (int i = 0; i < k; i++) bitOf[names[i]] = 1 << i; // i번째 권한의 값은 2^i        int q = int.Parse(Console.ReadLine());        var sb = new StringBuilder();        for (int j = 0; j < q; j++)        {            string[] t = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            int mask = int.Parse(t[0]);            string mode = t[1];            bool all = true, any = false;            for (int w = 2; w < t.Length; w++)            {                bool has = (mask & bitOf[t[w]]) != 0; // C#은 int를 bool로 쓸 수 없어 != 0이 꼭 필요하다                all = all && has;                any = any || has;            }            bool ok = mode == "all" ? all : mode == "any" ? any : !any;            sb.Append(ok ? "예" : "아니요").Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 34 줄
#include <iostream>#include <sstream>#include <string>#include <unordered_map> int main() {    int k;    std::cin >> k;    std::unordered_map<std::string, int> bitOf;    for (int i = 0; i < k; i++) {        std::string name;        std::cin >> name;        bitOf[name] = 1 << i; // i번째 권한의 값은 2^i    }    int q;    std::cin >> q;    std::string line;    std::getline(std::cin, line); // q 뒤에 남은 줄바꿈    for (int j = 0; j < q; j++) {        std::getline(std::cin, line);        std::istringstream ss(line);        int mask;        std::string mode, w;        ss >> mask >> mode;        bool all = true, any = false;        while (ss >> w) {            bool has = (mask & bitOf[w]) != 0; // 괄호 필수: != 가 & 보다 먼저 계산된다            all = all && has;            any = any || has;        }        bool ok = mode == "all" ? all : mode == "any" ? any : !any;        std::cout << (ok ? "예" : "아니요") << '\n';    }}
Cmain.c · 32 줄
#include <stdbool.h>#include <stdio.h>#include <string.h> int main(void) {    int k;    char names[30][11];    scanf("%d", &k);    for (int i = 0; i < k; i++) scanf("%10s", names[i]);    int q;    scanf("%d", &q);    for (int j = 0; j < q; j++) {        int mask;        char mode[5];        scanf("%d %4s", &mask, mode);        bool all = true, any = false;        /* 이름들은 줄 끝까지 이어진다: 다음 글자가 줄바꿈이면 멈춘다 */        int c;        while ((c = getchar()) == ' ') {            char w[11];            scanf("%10s", w);            int i = 0;            while (strcmp(names[i], w) != 0) i++;            bool has = (mask & (1 << i)) != 0; /* 괄호 필수: != 가 & 보다 먼저 계산된다 */            all = all && has;            any = any || has;        }        bool ok = strcmp(mode, "all") == 0 ? all : strcmp(mode, "any") == 0 ? any : !any;        puts(ok ? "예" : "아니요");    }    return 0;}
Craykonmain.cray · 44 줄
// 크레이콘에는 비트 연산이 없다: mask를 2^i로 나눈 몫이 홀수이면 i번째 비트가 켜져 있다켜졌나(mask, 값){    돌려주기 수학.몫(mask, 값) % 2 == 1;} k = 콘솔.줄읽기().수로변환();names = 콘솔.줄읽기().나누기();bitOf = 사전();값 = 1;반복 (i = 0; i < k; i++){    bitOf[names[i]] = 값; // i번째 권한의 값은 2^i: 1에서 시작해 두 배씩    값 *= 2;}q = 콘솔.줄읽기().수로변환();반복 (j = 0; j < q; j++){    t = 콘솔.줄읽기().나누기();    mask = t[0].수로변환();    mode = t[1];    모두 = 참;    하나라도 = 거짓;    반복 (w = 2; w < t.개수; w++)    {        있음 = 켜졌나(mask, bitOf[t[w]]);        모두 = 모두 && 있음;        하나라도 = 하나라도 || 있음;    }    ok = 거짓;    만약 (mode == "all")    {        ok = 모두;    }    아니면 만약 (mode == "any")    {        ok = 하나라도;    }    아니면    {        ok = !하나라도;    }    콘솔.쓰기(ok ? "예" : "아니요");}