{ }codelper
更新字典用字典计数P0228

只算最后一票的投票

用手机投票选班长。
投票期间同一个学生可以重新投票任意次,每个学生只算最后投的那一票。
第一行给出候选人数 k,第二行给出 k 个候选人名字,用一个空格分开。
第三行给出收到的票数 n,接下来 n 行按收到的顺序每行给出一票“学号 候选人名”,用一个空格分开。
学号按字符串原样比较。
所以 "1" 和 "01" 是不同的学生。
按第二行候选人出现的顺序,对每个候选人输出一行:名字和得票数,用一个空格分开。
一票也没得到的候选人也输出 0。
最后一行输出被计票的学生人数(不同学号的个数)。

输入
1 ≤ k ≤ 20,1 ≤ n ≤ 5,000。
候选人名互不相同,由 1~10 个小写英文字母组成。
学号由小写英文字母和数字组成,1~8 个字符。
票上的候选人名一定是候选人之一
输出
k 行(候选人名、票数),然后一行(学生人数)
样例 1 · stdin
3
mina joon hana
5
s1 mina
s2 joon
s1 hana
s3 joon
s2 mina
stdout
mina 1
joon 1
hana 1
3
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

把每个学生当前算的票放在字典里,新票来了就覆盖那个值。
陷阱在于很多语言里“覆盖”和“不覆盖”的写法很像。
Python d[k] = v、JS/TS map.set(k, v)、Craykon d[k] = v 会替换原来的值。
Java put 也会覆盖,但 putIfAbsent 只在键不存在时才放入。
C# 索引器 d[k] = v 会覆盖,但 d.Add(k, v) 遇到已有的键会抛出 ArgumentException。
C++ m[k] = v 会覆盖,但 m.insert({k, v}) 和 emplace 在键已存在时什么也不做,留下的是第一票。
先全部读完,再只遍历字典的值按候选人计数,就不用担心改票时忘了从原候选人那里减 1。
学号保持为字符串。
在 JS 里用 Number 转换,"1" 和 "01" 会变成同一个学生。
C 没有字典,要把学号记在数组里,用 strcmp 从前往后找。

Pythonmain.py · 13 行
k = int(input())cands = input().split()n = int(input())vote = {}                       # 학생 번호 → 지금 센 표for _ in range(n):    voter, cand = input().split()    vote[voter] = cand          # 있던 표는 덮어쓴다count = {c: 0 for c in cands}for cand in vote.values():    count[cand] += 1for c in cands:    print(c, count[c])print(len(vote))
JavaScriptmain.js · 18 行
const tok = require("fs").readFileSync(0, "utf8").trim().split(/\s+/);let p = 0;const k = Number(tok[p++]);const cands = tok.slice(p, p + k);p += k;const n = Number(tok[p++]);// 학생 번호는 문자열 그대로 둔다("01"과 "1"은 다른 학생)const vote = new Map();for (let i = 0; i < n; i++) {  const voter = tok[p++];  const cand = tok[p++];  vote.set(voter, cand); // set은 있던 값을 덮어쓴다}const count = new Map(cands.map((c) => [c, 0]));for (const cand of vote.values()) count.set(cand, count.get(cand) + 1);const out = cands.map((c) => `${c} ${count.get(c)}`);out.push(String(vote.size));console.log(out.join("\n"));
TypeScriptmain.ts · 18 行
import { readFileSync } from "node:fs";const tok: string[] = readFileSync(0, "utf8").trim().split(/\s+/);let p = 0;const k: number = Number(tok[p++]);const cands: string[] = tok.slice(p, p + k);p += k;const n: number = Number(tok[p++]);const vote = new Map<string, string>();for (let i = 0; i < n; i++) {  const voter: string = tok[p++];  const cand: string = tok[p++];  vote.set(voter, cand); // set은 있던 값을 덮어쓴다}const count = new Map<string, number>(cands.map((c): [string, number] => [c, 0]));for (const cand of vote.values()) count.set(cand, (count.get(cand) ?? 0) + 1);const out: string[] = cands.map((c) => `${c} ${count.get(c)}`);out.push(String(vote.size));console.log(out.join("\n"));
JavaMain.java · 28 行
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.HashMap;import java.util.Map;import java.util.StringTokenizer; public class Main {    public static void main(String[] args) throws Exception {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int k = Integer.parseInt(br.readLine().trim());        String[] cands = br.readLine().trim().split("\\s+");        int n = Integer.parseInt(br.readLine().trim());        Map<String, String> vote = new HashMap<>();        for (int i = 0; i < n; i++) {            StringTokenizer st = new StringTokenizer(br.readLine());            String voter = st.nextToken();            String cand = st.nextToken();            vote.put(voter, cand); // put은 덮어쓴다(putIfAbsent는 처음 값을 지킨다)        }        Map<String, Integer> count = new HashMap<>();        for (String c : cands) count.put(c, 0);        for (String cand : vote.values()) count.merge(cand, 1, Integer::sum);        StringBuilder out = new StringBuilder();        for (String c : cands) out.append(c).append(' ').append(count.get(c)).append('\n');        out.append(vote.size()).append('\n');        System.out.print(out);    }}
C#Main.cs · 27 行
using System;using System.Collections.Generic;using System.Text; class Program{    static void Main()    {        int k = int.Parse(Console.ReadLine().Trim());        string[] cands = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int n = int.Parse(Console.ReadLine().Trim());        var vote = new Dictionary<string, string>();        for (int i = 0; i < n; i++)        {            string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            // 인덱서 대입은 덮어쓴다. Add는 이미 있는 열쇠에서 예외를 던진다            vote[p[0]] = p[1];        }        var count = new Dictionary<string, int>();        foreach (string c in cands) count[c] = 0;        foreach (string cand in vote.Values) count[cand]++;        var sb = new StringBuilder();        foreach (string c in cands) sb.Append(c).Append(' ').Append(count[c]).Append('\n');        sb.Append(vote.Count).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 23 行
#include <iostream>#include <string>#include <unordered_map>#include <vector> int main() {    std::ios::sync_with_stdio(false);    int k, n;    std::cin >> k;    std::vector<std::string> cands(k);    for (auto& c : cands) std::cin >> c;    std::cin >> n;    std::unordered_map<std::string, std::string> vote;    for (int i = 0; i < n; i++) {        std::string voter, cand;        std::cin >> voter >> cand;        vote[voter] = cand; // operator[]는 덮어쓴다. insert·emplace는 있던 값을 그대로 둔다    }    std::unordered_map<std::string, int> count;    for (const auto& [voter, cand] : vote) count[cand]++;    for (const auto& c : cands) std::cout << c << ' ' << count[c] << '\n';    std::cout << vote.size() << '\n';}
Cmain.c · 32 行
#include <stdio.h>#include <string.h> /* C에는 사전이 없어서, 학생 번호와 그 학생의 표(후보 번호)를 배열에 적고 앞에서부터 찾는다 */static char voters[5000][9];static int choice[5000];static char cands[20][11]; int main(void) {    int k, n, m = 0;    scanf("%d", &k);    for (int i = 0; i < k; i++) scanf("%10s", cands[i]);    scanf("%d", &n);    for (int i = 0; i < n; i++) {        char voter[16], cand[16];        scanf("%15s %15s", voter, cand);        int c = 0;        while (strcmp(cands[c], cand) != 0) c++;        int j = 0;        while (j < m && strcmp(voters[j], voter) != 0) j++;        if (j == m) {            strcpy(voters[m], voter);            m++;        }        choice[j] = c; /* 있던 표는 덮어쓴다 */    }    int count[20] = {0};    for (int j = 0; j < m; j++) count[choice[j]]++;    for (int i = 0; i < k; i++) printf("%s %d\n", cands[i], count[i]);    printf("%d\n", m);    return 0;}
Craykonmain.cray · 24 行
k = 控制台.读行().转数字();cands = 控制台.读行().去空白().分割(" ");n = 控制台.读行().转数字();vote = 字典();循环 (i = 0; i < n; i++){    p = 控制台.读行().去空白().分割(" ");    // 같은 열쇠에 다시 넣으면 있던 표를 덮어쓴다    vote[p[0]] = p[1];}count = 字典();遍历 (c 在 cands){    count[c] = 0;}遍历 (cand 在 vote.值列表){    count[cand] = count[cand] + 1;}遍历 (c 在 cands){    控制台.输出(c + " " + count[c]);}控制台.输出(vote.数量);