[NOIP 2003 普及组] 乒乓球

GitHub跳转原题关系图返回列表

先读到 E 前的所有 W/L 记录,再分别按 11 分制和 21 分制模拟分局。

OJ: luogu

题目 ID: P1042

难度:普及-

标签:模拟字符串python

日期: 2026-07-15 21:22

题意

输入一串 W/L 比赛记录,以 E 结束。分别按 11 分制和 21 分制输出每局比分。某局至少达到目标分,且双方分差至少为 2 时结束。

思路

先读取所有输入字符,遇到 E 就停止,只保留 WL

然后写一个函数:

python
build_scores(records, target)

它按照给定目标分制模拟比赛:

  1. 当前局 W 分和 L 分从 0 开始;
  2. 扫描每个球的胜负,给对应一方加分;
  3. 如果 max(win, lose) >= targetabs(win-lose) >= 2,当前局结束并清零;
  4. 所有记录扫完后,还要输出正在进行的最后一局。

Python 知识

  • /home/rainboy/mycode/hugo-blog/content/program_language/python/oj_input_output_cheatsheet.md:不确定行数时,可以用 sys.stdin.read() 读取全部输入。
  • /home/rainboy/mycode/hugo-blog/content/program_language/python/input_output_and_strings.md:f-string 适合格式化 win:lose
  • break 可以在遇到 E 时停止解析。
  • 把分制作为函数参数,避免给 11 分制和 21 分制写两份代码。

代码

python
import sys


def parse_records():
    records = []
    for ch in sys.stdin.read():
        if ch == "E":
            break
        if ch == "W" or ch == "L":
            records.append(ch)
    return records


def build_scores(records, target):
    scores = []
    win = 0
    lose = 0

    for ch in records:
        if ch == "W":
            win += 1
        else:
            lose += 1

        if max(win, lose) >= target and abs(win - lose) >= 2:
            scores.append((win, lose))
            win = 0
            lose = 0

    scores.append((win, lose))
    return scores


records = parse_records()

for win, lose in build_scores(records, 11):
    print(f"{win}:{lose}")

print()

for win, lose in build_scores(records, 21):
    print(f"{win}:{lose}")
cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-27 00:00
 * update_at: 2026-07-27 00:00
 */
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100000 + 5;

char records[MAXN]; // 保存所有的比赛记录(W/L)
int  len;           // 有效记录长度

// 按 target 分制模拟比赛,输出每局比分
void build_scores(int target) {
    int win = 0, lose = 0; // 当前局 W 和 L 的得分
    for (int i = 0; i < len; i++) {
        if (records[i] == 'W') win++;
        else                   lose++;

        // 当前局结束条件:有人 >= target 且分差 >= 2
        if (max(win, lose) >= target && abs(win - lose) >= 2) {
            cout << win << ":" << lose << "\n";
            win = 0; lose = 0;
        }
    }
    // 输出未完成的最后一局(可能 0:0)
    cout << win << ":" << lose << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    char ch;
    while (cin >> ch) {
        if (ch == 'E') break;
        if (ch == 'W' || ch == 'L')
            records[len++] = ch;
    }

    build_scores(11);  // 11 分制
    cout << "\n";
    build_scores(21);  // 21 分制

    return 0;
}

复杂度

设有效记录长度为 n,分别模拟两种分制,时间复杂度是 O(n)O(n),空间复杂度是 O(n)O(n)

总结

模拟题先把输入清洗成统一的事件序列,再写一个可复用的模拟函数。不同规则只作为参数传入。