[NOIP2003-普及] 乒乓球

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

对 W/L 比分序列分别按 11 分制和 21 分制逐球模拟计分:达到局分且分差至少 2 时一局结束,末尾未完成局也要输出当前比分。

OJ: roj

题目 ID: 3520

难度:入门

标签:模拟字符串

创建: 2026-10-02 05:04

更新: 2026-10-06 13:02

题目描述

一份比赛记录由大写 W、L 组成(W 表示华华得 1 分,L 表示对手得 1 分),读到 E 表示记录结束,E 及其之后的内容全部忽略。某一方得分达到 nn 分且双方分差 ⩾2\geqslant 2 时,该局立即结束、比分清零开始下一局。要求分别输出 1111 分制和 2121 分制下每一局的比分 a:b(a 为华华得分),记录末尾尚未结束的一局也要输出其当前比分(一局刚开始时输出 0:0),两部分之间用一个空行分隔。每行至多 25 个字母,最多 2500 行。

例如输入 WWWWWWWWWWWWWWWWWWWWWWLWE 的输出为:11 分制下 11:0、11:0、1:1,空一行后 21 分制下 21:0、2:1。

思路

纯粹的模拟题:把记录截断于 E 后,用一个以局分 nn 为参数的过程对同一序列各独立扫一遍,逐球累加 W/L 得分,每加一分就检查"某方得分 ⩾n\geqslant n 且分差 ⩾2\geqslant 2",成立则记下一局比分并清零。扫描结束后把当前比分作为残局输出(哪怕 0:0),两种分制互不影响。

参考代码

Python 版:

python
"""NOIP2003 普及组 乒乓球:11/21 分制逐球模拟。

一局结束条件:某方得分 >= n 且分差 >= 2;末尾未打完的一局也输出当前比分。
"""
import sys


def play(s: str, n: int) -> list[str]:
    """按 n 分制扫描比分序列,返回每局(含末尾未完成局)的 'a:b' 列表。"""
    res: list[str] = []
    a = b = 0
    for c in s:
        if c == 'W':
            a += 1
        elif c == 'L':
            b += 1
        if max(a, b) >= n and abs(a - b) >= 2:  # 达到 n 分且分差 >= 2,本局结束
            res.append(f"{a}:{b}")
            a = b = 0
    res.append(f"{a}:{b}")  # 最后一局可能未结束,输出当前比分(可能 0:0)
    return res


def main() -> None:
    s = sys.stdin.read().split('E')[0]  # 忽略 E 及之后的所有内容
    r11, r21 = play(s, 11), play(s, 21)
    sys.stdout.write('\n'.join(r11) + '\n\n' + '\n'.join(r21) + '\n')


if __name__ == '__main__':
    main()

C++ 版(同一算法):

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-10-06 13:02
 * update_at: 2026-10-06 13:02
 */

#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;

typedef long long ll;

const int MAXN = 2505 * 25 + 5; // 每行至多 25 个字母,最多 2500 行

char buf[100];   // 读入的每一行
char rec[MAXN];  // 拼接后的完整比分记录(截断于 E 之前)
ll len = 0;      // 有效记录的长度

// 按 n 分制对记录从头到尾扫一遍,输出每局比分(含末尾残局)
void play(int n) {
    ll a = 0, b = 0; // a: 华华(W)得分, b: 对手(L)得分
    for (ll i = 0; i < len; ++i) {
        if (rec[i] == 'W') a++;
        else b++;
        // 一局结束:某方达到局分 n 且分差至少 2,两者缺一不可
        if (max(a, b) >= n && llabs(a - b) >= 2) {
            printf("%lld:%lld\n", a, b);
            a = 0;
            b = 0;
        }
    }
    // 末尾未打完的一局(可能 0:0)也要输出
    printf("%lld:%lld\n", a, b);
}

int main() {
    // 把所有行拼成一条记录,读到 E 就停止,E 之后内容全部忽略
    while (scanf("%s", buf) == 1) {
        for (ll i = 0; buf[i] != '\0'; ++i) {
            if (buf[i] == 'E') {
                rec[len] = '\0';
                play(11);
                printf("\n");
                play(21);
                return 0;
            }
            rec[len++] = buf[i];
        }
    }
    // 没有 E 也能结束:整条输入都是比分
    rec[len] = '\0';
    play(11);
    printf("\n");
    play(21);
    return 0;
}