2 2
10
mina hi
jun hi
mina HI
jun yo
mina hi
mina Hi
mina hi
jun yo
ab c
a bc
stdout
mina hi
jun hi
jun yo
mina hi
ab c
a bc
3 1
mina
main.py
エラー一覧00F8 ↓ · ⇧F8 ↑
入力(stdin)
実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。
$ 準備完了
コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。
ほかの言語では?言語別の解答を見る · 8 言語の解答
この問題は「リストにあるか」を 2 回たずねます。 ブロックリストには名前 1 つを、画面リストには(名前、単語)の組をたずねます。 文字列 1 つを探すのは Python name in blocked、JS・TS blocked.includes(name)、Java blocked.contains(name)、C# blocked.Contains(name)、C++ std::find(blocked.begin(), blocked.end(), name) != blocked.end()、Craykon blocked.含む(name) で、C は strcmp で 1 つずつ比べるループを書きます。 組を探すところで言語が分かれます。 Python のタプル (name, low) in screen、C++ の std::pair に対する std::find、C# のタプルを入れた List<(string, string)> の Contains、Java の List.of(name, low) を入れたリストの contains は中の値を比べます。 落とし穴その一:JS・TS screen.includes([name, low])、Java List<String[]> の contains(new String[] {name, low})、Craykon screen.含む([name, low]) は、中身が同じでも今作ったばかりの別の配列・リストなので常に偽です。 エラーも出ずに連投を 1 つも捕まえられず、例の 3 番目のメッセージ mina HI がそのまま出力されます。 JS・TS は screen.some(([a, b]) => a === name && b === low) で中身を比べ、Craykon は名前のリストと単語のリストを並べて持ち、位置ごとに比べます。 落とし穴その二:組を 1 つの文字列につないで探すこともできますが、区切りなしで name + low とつなぐと ab + c と a + bc がどちらも abc になり、例の最後のメッセージ a bc が連投として弾かれます。 名前にも単語にも出ない空白を間に入れます。 落とし穴その三:大文字と小文字を区別しないためには、入れるときも探すときも小文字にした単語を使います(Python lower()、JS・TS toLowerCase()、Java toLowerCase(Locale.ROOT)、C# ToLowerInvariant()、C・C++ は 1 文字ずつ tolower、Craykon 小文字())。 変えないと mina HI が連投でなくなります。 出力は受け取ったとおりなので、元の単語も持っておきます。 落とし穴その四:名前を見ずに単語だけを探すと、例の 2 番目のメッセージ jun hi のように他の人の同じ発言まで連投になります。 落とし穴その五:連投として弾いたメッセージを画面リストに入れると、画面にあったメッセージが押し出されたり残りすぎたりして、例の 5 番目のメッセージ mina hi が誤って弾かれます。 落とし穴その六:入れたあと >= k のときに取り除くと、画面リストには k − 1 個しか残りません。 先頭を取り除くのは Python pop(0)、JS・TS shift()、Java remove(0)、C# RemoveAt(0)、C++ erase(begin())、Craykon 位置で取り除く(0) で、C は配列を 1 つずつ前に詰めます。 落とし穴その七:ブロックリストを先にたずねます。 画面リストを先にたずねると、すでにブロックされた mina の 7 番目のメッセージが無視ではなく連投として数えられ、3 1 が 4 0 になります。
Pythonmain.py · 28 行
import syslines = sys.stdin.read().split("\n")k, s = map(int, lines[0].split())n = int(lines[1])screen = [] # 화면에 남은 (이름, 소문자 낱말) 쌍, 오래된 것이 앞blocked = [] # 차단된 이름, 차단된 차례대로warn = {}repeats = ignored = 0out = []for i in range(n): name, word = lines[2 + i].split() key = (name, word.lower()) if name in blocked: ignored += 1 elif key in screen: # 튜플은 값으로 비교한다 repeats += 1 warn[name] = warn.get(name, 0) + 1 if warn[name] == s: blocked.append(name) else: out.append(f"{name} {word}") screen.append(key) if len(screen) > k: screen.pop(0)out.append(f"{repeats} {ignored}")out.append(" ".join(blocked) if blocked else "-")print("\n".join(out))
JavaScriptmain.js · 28 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [k, s] = lines[0].trim().split(/\s+/).map(Number);const n = Number(lines[1]);const screen = []; // 화면에 남은 [이름, 소문자 낱말] 쌍, 오래된 것이 앞const blocked = []; // 차단된 이름, 차단된 차례대로const warn = new Map();let repeats = 0;let ignored = 0;const out = [];for (let i = 0; i < n; i++) { const [name, word] = lines[2 + i].trim().split(/\s+/); const low = word.toLowerCase(); if (blocked.includes(name)) { ignored++; } else if (screen.some(([a, b]) => a === name && b === low)) { // includes([name, low])는 새 배열이라 늘 false다. 속을 하나씩 견준다 repeats++; warn.set(name, (warn.get(name) ?? 0) + 1); if (warn.get(name) === s) blocked.push(name); } else { out.push(`${name} ${word}`); screen.push([name, low]); if (screen.length > k) screen.shift(); }}out.push(`${repeats} ${ignored}`);out.push(blocked.length > 0 ? blocked.join(" ") : "-");console.log(out.join("\n"));
TypeScriptmain.ts · 30 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const [k, s]: number[] = lines[0].trim().split(/\s+/).map(Number);const n: number = Number(lines[1]);const screen: [string, string][] = []; // 화면에 남은 [이름, 소문자 낱말] 쌍, 오래된 것이 앞const blocked: string[] = []; // 차단된 이름, 차단된 차례대로const warn = new Map<string, number>();let repeats = 0;let ignored = 0;const out: string[] = [];for (let i = 0; i < n; i++) { const [name, word]: string[] = lines[2 + i].trim().split(/\s+/); const low: string = word.toLowerCase(); if (blocked.includes(name)) { ignored++; } else if (screen.some(([a, b]) => a === name && b === low)) { // includes([name, low])는 새 배열이라 늘 false다. 속을 하나씩 견준다 repeats++; const count: number = (warn.get(name) ?? 0) + 1; warn.set(name, count); if (count === s) blocked.push(name); } else { out.push(`${name} ${word}`); screen.push([name, low]); if (screen.length > k) screen.shift(); }}out.push(`${repeats} ${ignored}`);out.push(blocked.length > 0 ? blocked.join(" ") : "-");console.log(out.join("\n"));
JavaMain.java · 44 行
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Locale;import java.util.Map;public class Main { public static void main(String[] args) throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String[] first = in.readLine().trim().split(" "); int k = Integer.parseInt(first[0]); int s = Integer.parseInt(first[1]); int n = Integer.parseInt(in.readLine().trim()); // List.of(이름, 낱말)은 equals가 속을 견주므로 contains로 찾을 수 있다(String[]는 안 된다) List<List<String>> screen = new ArrayList<>(); List<String> blocked = new ArrayList<>(); Map<String, Integer> warn = new HashMap<>(); int repeats = 0; int ignored = 0; StringBuilder out = new StringBuilder(); for (int i = 0; i < n; i++) { String[] parts = in.readLine().trim().split(" "); String name = parts[0]; String word = parts[1]; List<String> key = List.of(name, word.toLowerCase(Locale.ROOT)); if (blocked.contains(name)) { ignored++; } else if (screen.contains(key)) { repeats++; int count = warn.merge(name, 1, Integer::sum); if (count == s) blocked.add(name); } else { out.append(name).append(' ').append(word).append('\n'); screen.add(key); if (screen.size() > k) screen.remove(0); } } out.append(repeats).append(' ').append(ignored).append('\n'); out.append(blocked.isEmpty() ? "-" : String.join(" ", blocked)).append('\n'); System.out.print(out); }}
C#Main.cs · 45 行
using System;using System.Collections.Generic;using System.Text;class Program{ static void Main() { string[] first = Console.ReadLine().Trim().Split(' '); int k = int.Parse(first[0]); int s = int.Parse(first[1]); int n = int.Parse(Console.ReadLine()); // 튜플 (string, string)은 값으로 비교하므로 Contains로 찾을 수 있다(string[]은 안 된다) var screen = new List<(string, string)>(); var blocked = new List<string>(); var warn = new Dictionary<string, int>(); int repeats = 0, ignored = 0; var sb = new StringBuilder(); for (int i = 0; i < n; i++) { string[] parts = Console.ReadLine().Trim().Split(' '); string name = parts[0], word = parts[1]; var key = (name, word.ToLowerInvariant()); if (blocked.Contains(name)) { ignored++; } else if (screen.Contains(key)) { repeats++; warn[name] = warn.GetValueOrDefault(name, 0) + 1; if (warn[name] == s) blocked.Add(name); } else { sb.Append(name).Append(' ').Append(word).Append('\n'); screen.Add(key); if (screen.Count > k) screen.RemoveAt(0); } } sb.Append(repeats).Append(' ').Append(ignored).Append('\n'); sb.Append(blocked.Count > 0 ? string.Join(" ", blocked) : "-").Append('\n'); Console.Write(sb); }}
C++main.cpp · 42 行
#include <algorithm>#include <cctype>#include <iostream>#include <map>#include <string>#include <utility>#include <vector>using namespace std;int main() { int k, s, n; cin >> k >> s >> n; vector<pair<string, string>> screen; // 화면에 남은 (이름, 소문자 낱말), 오래된 것이 앞 vector<string> blocked; // 차단된 이름, 차단된 차례대로 map<string, int> warn; int repeats = 0, ignored = 0; for (int i = 0; i < n; i++) { string name, word; cin >> name >> word; string low = word; for (char &c : low) c = (char)tolower((unsigned char)c); pair<string, string> key{name, low}; if (find(blocked.begin(), blocked.end(), name) != blocked.end()) { ignored++; } else if (find(screen.begin(), screen.end(), key) != screen.end()) { // pair는 값으로 비교한다 repeats++; if (++warn[name] == s) blocked.push_back(name); } else { cout << name << ' ' << word << '\n'; screen.push_back(key); if ((int)screen.size() > k) screen.erase(screen.begin()); } } cout << repeats << ' ' << ignored << '\n'; if (blocked.empty()) { cout << "-\n"; } else { for (size_t i = 0; i < blocked.size(); i++) cout << (i ? " " : "") << blocked[i]; cout << '\n'; } return 0;}
Cmain.c · 68 行
#include <ctype.h>#include <stdio.h>#include <string.h>#define MAXK 50#define MAXN 2000static char scr_name[MAXK][9], scr_word[MAXK][9]; /* 화면 목록, 오래된 것이 앞 */static char people[MAXN][9]; /* 도배한 적이 있는 이름 */static int warn[MAXN];static char blocked[MAXN][9];/* C에는 목록 찾기가 없다. strcmp로 하나씩 견준다 */static int find_name(char list[][9], int count, const char *name) { for (int i = 0; i < count; i++) if (strcmp(list[i], name) == 0) return i; return -1;}int main(void) { int k, s, n; if (scanf("%d %d %d", &k, &s, &n) != 3) return 1; int screen = 0, npeople = 0, nblocked = 0, repeats = 0, ignored = 0; for (int i = 0; i < n; i++) { char name[9], word[9], low[9]; if (scanf("%8s %8s", name, word) != 2) return 1; size_t len = strlen(word); for (size_t j = 0; j <= len; j++) low[j] = (char)tolower((unsigned char)word[j]); if (find_name(blocked, nblocked, name) >= 0) { ignored++; continue; } int on_screen = 0; for (int j = 0; j < screen; j++) if (strcmp(scr_name[j], name) == 0 && strcmp(scr_word[j], low) == 0) on_screen = 1; if (on_screen) { repeats++; int p = find_name(people, npeople, name); if (p < 0) { p = npeople++; strcpy(people[p], name); warn[p] = 0; } if (++warn[p] == s) strcpy(blocked[nblocked++], name); } else { printf("%s %s\n", name, word); if (screen == k) { /* 꽉 찼으면 가장 오래된 것을 빼고 한 칸씩 당긴다 */ for (int j = 1; j < screen; j++) { strcpy(scr_name[j - 1], scr_name[j]); strcpy(scr_word[j - 1], scr_word[j]); } screen--; } strcpy(scr_name[screen], name); strcpy(scr_word[screen], low); screen++; } } printf("%d %d\n", repeats, ignored); if (nblocked == 0) { printf("-\n"); } else { for (int i = 0; i < nblocked; i++) printf("%s%s", i ? " " : "", blocked[i]); printf("\n"); } return 0;}