어떤 서비스는 사용자의 권한을 정수 하나(권한 값)에 모아 둔다.
첫 줄에 권한의 수 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
오류 목록00F8 ↓ · ⇧F8 ↑
입력(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"));
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 ? "예" : "아니요");}