A lock in a bicycle shed has its owner's name and several secret numbers, in order, on record.
A record is one line of the form "name k number1 … numberk". k is how many numbers there are.
The first line gives the registered record.
The second line gives the number of attempts n, and each of the next n lines gives one attempt as a record of the same form.
Two records are the same when the names are the same, the counts of numbers are the same, and the numbers are the same at every position.
Numbers are compared as numbers. A number may be written with zeros in front, so 007 and 7 look different but are the same number.
The same numbers in a different order are a different record, and a record that matches only at the front but has a different count is a different record.
Print one line per attempt.
If the attempt is the same as the registered record, print "open".
Otherwise, if it is the same as the attempt just before it, print "again".
If neither, print "no".
The first attempt has no attempt before it.
Input
1 ≤ n ≤ 1,000. A name is 1 to 10 lowercase English letters. 1 ≤ k ≤ 10, and each number is an integer from 0 to 1,000,000,000. Numbers are written with 1 to 10 digits, without commas, and may have zeros in front (007 is 7, 00 is 0). k and n have no zeros in front. Words on a line are separated by one space.
Output
n lines. Each line is one of "open", "again", "no"
Example 1 · stdin
mina 3 7 300 12
6
mina 3 7 300 12
mina 2 7 300
mina 2 7 300
mino 3 7 300 12
mina 3 7 12 300
mina 3 7 300 12
stdout
open
no
again
no
no
open
Example 2 · stdin
bike 2 1 23
6
bike 2 12 3
bike 1 123
bike 1 0123
bike 2 01 23
bike 2 1 023
bike 2 10 23
stdout
no
no
again
open
open
no
main.py
Error List00F8 ↓ · ⇧F8 ↑
Input (stdin)
When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).
$ Ready
Open this on a computer to write and run code. On mobile you can read the problem and the solutions.
In other languagesShow solutions by language · 8 languages
This problem separates "equal in value" from "the very same thing". Two records read separately from the input are different objects even when their contents match, so which question your == asks changes the answer. In Python == compares values, so (name, numbers) == key compares lengths and every position, and is asks whether it is the same object. In C++ == on std::string and std::vector compares values too, so one line in the struct is enough: bool operator==(const Record&) const = default; (C++20). In Java == on objects asks whether they are the same object. Compare strings with a.equals(b) and arrays with Arrays.equals(a, b) (a List's equals compares the elements). In C# == on string compares contents, but on arrays both == and Equals ask only whether it is the same array, so use a.SequenceEqual(b). In JavaScript and TypeScript === on strings compares contents and === on arrays asks only whether it is the same array, so compare the lengths and then every position with every. In C, == between array names compares addresses, so use strcmp(a, b) == 0 for strings and a loop for the numbers (== between structs does not compile at all). In Craykon == on strings compares contents and == on lists asks whether it is the same list, so write a function that compares position by position. Six traps: (1) Comparing names with == in Java gives "no" everywhere, because strings read from input are always different objects. (2) Comparing elements of a Java List<Integer> with a.get(i) != b.get(i), or numbers in Python with is, seems to work for small numbers (Java -128 to 127, CPython -5 to 256) because those objects are made once and shared, then fails for a larger number such as 300. (3) Comparing arrays glued with join("") makes [1, 23], [12, 3] and [123] all "123" (example 2). If you glue, put a separator in: join(","). (4) Python zip stops at the shorter side, so without comparing lengths first a record that matches only at the front counts as the same. (5) In C, remembering only the address of the previous attempt (prev = &cur) instead of copying it means the previous attempt changes the moment the next one is read into the same place, and you compare the attempt with itself. Struct assignment prev = cur copies the contents. (6) Comparing whole lines or words as strings says 007 and 7 differ. Turn the numbers into numbers first, then compare (Python int, JS Number, Java Integer.parseInt, C# int.Parse, Craykon ToNumber). In C read them with %d in scanf. %i reads a number that starts with 0 as octal, so 010 becomes 8.
Pythonmain.py · 19 lines
def read_record(line): """'이름 개수 번호…' 한 줄을 (이름, 번호 목록)으로.""" parts = line.split() return parts[0], [int(x) for x in parts[2:]]key = read_record(input())n = int(input())prev = None # 첫 시도에는 앞 시도가 없다for _ in range(n): attempt = read_record(input()) # 튜플·목록의 ==는 길이와 자리마다의 값을 비교한다(`is`는 같은 객체인지를 묻는다) if attempt == key: print("open") elif attempt == prev: print("again") else: print("no") prev = attempt
JavaScriptmain.js · 25 lines
const lines = require("fs").readFileSync(0, "utf8").split("\n");// "이름 개수 번호…" 한 줄을 기록으로function readRecord(line) { const parts = line.trim().split(" "); return { name: parts[0], codes: parts.slice(2).map(Number) };}// 배열의 ===는 같은 배열인지만 물으므로, 길이와 자리마다의 값을 직접 비교한다function sameRecord(a, b) { return a.name === b.name && a.codes.length === b.codes.length && a.codes.every((x, i) => x === b.codes[i]);}const key = readRecord(lines[0]);const n = Number(lines[1]);const out = [];let prev = null; // 첫 시도에는 앞 시도가 없다for (let i = 2; i < 2 + n; i++) { const attempt = readRecord(lines[i]); if (sameRecord(attempt, key)) out.push("open"); else if (prev !== null && sameRecord(attempt, prev)) out.push("again"); else out.push("no"); prev = attempt;}console.log(out.join("\n"));
TypeScriptmain.ts · 31 lines
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");interface LockRecord { name: string; codes: number[];}// "이름 개수 번호…" 한 줄을 기록으로function readRecord(line: string): LockRecord { const parts = line.trim().split(" "); return { name: parts[0], codes: parts.slice(2).map(Number) };}// 배열의 ===는 같은 배열인지만 물으므로, 길이와 자리마다의 값을 직접 비교한다function sameRecord(a: LockRecord, b: LockRecord): boolean { return a.name === b.name && a.codes.length === b.codes.length && a.codes.every((x, i) => x === b.codes[i]);}const key = readRecord(lines[0]);const n = Number(lines[1]);const out: string[] = [];let prev: LockRecord | null = null; // 첫 시도에는 앞 시도가 없다for (let i = 2; i < 2 + n; i++) { const attempt = readRecord(lines[i]); if (sameRecord(attempt, key)) out.push("open"); else if (prev !== null && sameRecord(attempt, prev)) out.push("again"); else out.push("no"); prev = attempt;}console.log(out.join("\n"));
JavaMain.java · 43 lines
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.Arrays;public class Main { static String name(String[] parts) { return parts[0]; } static int[] codes(String[] parts) { int[] codes = new int[parts.length - 2]; for (int i = 0; i < codes.length; i++) codes[i] = Integer.parseInt(parts[i + 2]); return codes; } // 문자열은 equals, 배열은 Arrays.equals로 내용을 비교한다(==는 같은 객체인지만 묻는다) static boolean same(String nameA, int[] codesA, String nameB, int[] codesB) { return nameA.equals(nameB) && Arrays.equals(codesA, codesB); } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String[] first = in.readLine().trim().split(" "); String keyName = name(first); int[] keyCodes = codes(first); int n = Integer.parseInt(in.readLine().trim()); String prevName = null; // 첫 시도에는 앞 시도가 없다 int[] prevCodes = null; StringBuilder out = new StringBuilder(); for (int i = 0; i < n; i++) { String[] parts = in.readLine().trim().split(" "); String curName = name(parts); int[] curCodes = codes(parts); if (same(curName, curCodes, keyName, keyCodes)) out.append("open\n"); else if (prevName != null && same(curName, curCodes, prevName, prevCodes)) out.append("again\n"); else out.append("no\n"); prevName = curName; prevCodes = curCodes; } System.out.print(out); }}
C#Main.cs · 35 lines
using System;using System.Linq;using System.Text;class Program{ static int[] Codes(string[] parts) => parts.Skip(2).Select(int.Parse).ToArray(); // string의 ==는 내용을 비교하지만, 배열의 ==는 같은 배열인지만 물어서 SequenceEqual을 쓴다 static bool Same(string nameA, int[] codesA, string nameB, int[] codesB) => nameA == nameB && codesA.SequenceEqual(codesB); static void Main() { string[] first = Console.ReadLine().Trim().Split(' '); string keyName = first[0]; int[] keyCodes = Codes(first); int n = int.Parse(Console.ReadLine()); string prevName = null; // 첫 시도에는 앞 시도가 없다 int[] prevCodes = null; var sb = new StringBuilder(); for (int i = 0; i < n; i++) { string[] parts = Console.ReadLine().Trim().Split(' '); string curName = parts[0]; int[] curCodes = Codes(parts); if (Same(curName, curCodes, keyName, keyCodes)) sb.Append("open\n"); else if (prevName != null && Same(curName, curCodes, prevName, prevCodes)) sb.Append("again\n"); else sb.Append("no\n"); prevName = curName; prevCodes = curCodes; } Console.Write(sb); }}
C++main.cpp · 35 lines
#include <iostream>#include <string>#include <vector>struct Record { std::string name; std::vector<int> codes; // std::string과 std::vector의 ==는 내용을 비교하므로, 멤버끼리 비교하게만 하면 된다 bool operator==(const Record&) const = default;};Record read_record() { Record r; int count; std::cin >> r.name >> count; r.codes.resize(count); for (int& c : r.codes) std::cin >> c; return r;}int main() { Record key = read_record(); int n; std::cin >> n; Record prev; bool has_prev = false; // 첫 시도에는 앞 시도가 없다 for (int i = 0; i < n; i++) { Record cur = read_record(); if (cur == key) std::cout << "open\n"; else if (has_prev && cur == prev) std::cout << "again\n"; else std::cout << "no\n"; prev = cur; has_prev = true; }}
Cmain.c · 41 lines
#include <stdbool.h>#include <stdio.h>#include <string.h>typedef struct { char name[11]; int count; int codes[10];} Record;/* 번호는 %d로 읽어 수로 둔다: 앞에 0이 붙은 007도 7이 된다 */static void read_record(Record *r) { scanf("%10s %d", r->name, &r->count); for (int i = 0; i < r->count; i++) scanf("%d", &r->codes[i]);}/* 배열 이름끼리의 ==는 주소를 비교한다. 문자열은 strcmp로, 번호는 자리마다 비교한다 */static bool same_record(const Record *a, const Record *b) { if (strcmp(a->name, b->name) != 0) return false; if (a->count != b->count) return false; for (int i = 0; i < a->count; i++) if (a->codes[i] != b->codes[i]) return false; return true;}int main(void) { Record key, prev, cur; read_record(&key); int n; scanf("%d", &n); bool has_prev = false; /* 첫 시도에는 앞 시도가 없다 */ for (int i = 0; i < n; i++) { read_record(&cur); if (same_record(&cur, &key)) puts("open"); else if (has_prev && same_record(&cur, &prev)) puts("again"); else puts("no"); prev = cur; /* 구조체 대입은 내용을 통째로 복사한다 */ has_prev = true; } return 0;}
Craykonmain.cray · 50 lines
// "이름 개수 번호…" 한 줄을 [이름, 번호, 번호, …] 목록으로 바꾼다.// 번호는 수로 바꿔 둔다: 문자열 그대로면 "007"과 "7"이 다르다기록읽기(줄){ 낱말 = 줄.Trim().Split(" "); 기록 = [낱말[0]]; for (i = 2; i < 낱말.Count; i++) { 기록.Add(낱말[i].ToNumber()); } return 기록;}// 목록끼리의 ==는 같은 목록인지만 물으므로, 길이와 자리마다의 값을 직접 비교한다같은기록인가(a, b){ if (a.Count != b.Count) { return false; } for (i = 0; i < a.Count; i++) { if (a[i] != b[i]) { return false; } } return true;}등록 = 기록읽기(Console.ReadLine());n = Console.ReadLine().ToNumber();앞시도 = null; // 첫 시도에는 앞 시도가 없다for (k = 0; k < n; k++){ 시도 = 기록읽기(Console.ReadLine()); if (같은기록인가(시도, 등록)) { Console.WriteLine("open"); } else if (앞시도 != null && 같은기록인가(시도, 앞시도)) { Console.WriteLine("again"); } else { Console.WriteLine("no"); } 앞시도 = 시도;}