ACM 模式:算法竞赛输入输出与快速解题

针对算法竞赛和笔试的 ACM 模式专题:标准输入输出处理、Java/Python/C++ 三种语言模板、常见陷阱与调试技巧、以及笔试中的时间与空间优化策略。

ACM 模式:算法竞赛输入输出与快速解题

从 LeetCode 核心代码模式到 ACM 模式的过渡,是很多笔试新手的第一道坎。

LeetCode 给好了函数签名和测试用例调用,但笔试平台(牛客、赛码、HackerRank)通常要求你写完整的 main 函数,自己处理输入输出。本专题帮你快速上手 ACM 模式。


为什么需要 ACM 模式?

场景模式难点
LeetCode核心代码模式只需写函数体
大厂笔试ACM 模式需自己读输入、写输出
Codeforces/AtCoderACM 模式IO 量大,需要优化
软件设计师/蓝桥杯ACM 模式有格式要求,需严格匹配

ACM 模式的核心能力:

  1. 快速解析输入格式
  2. 处理多组测试用例(while 循环读入)
  3. 输出格式精确匹配(空格、换行)
  4. 大数据量下的快速 IO

Python 输入输出模板

基础模板

import sys

def solve():
    # 读取第一行:n 个数
    n = int(sys.stdin.readline().strip())

    # 读取第二行:n 个整数
    arr = list(map(int, sys.stdin.readline().split()))

    # 处理逻辑
    result = sum(arr)

    # 输出
    print(result)

if __name__ == "__main__":
    solve()

多组测试用例(T 组)

def solve():
    T = int(sys.stdin.readline())
    for _ in range(T):
        n = int(sys.stdin.readline())
        arr = list(map(int, sys.stdin.readline().split()))
        # 处理...
        print(result)

if __name__ == "__main__":
    solve()

读到 EOF 为止(未知行数)

def solve():
    for line in sys.stdin:
        nums = list(map(int, line.split()))
        if not nums:
            continue
        # 处理...
        print(result)

if __name__ == "__main__":
    solve()

快速 IO(处理 10^5 以上输入)

import sys

def fast_input():
    """一次性读取所有输入,适合大规模数据"""
    data = sys.stdin.buffer.read().split()
    it = iter(data)
    n = int(next(it))
    arr = [int(next(it)) for _ in range(n)]
    return n, arr

def solve():
    n, arr = fast_input()
    # 处理...
    sys.stdout.write(str(result))

if __name__ == "__main__":
    solve()

sys.stdin.buffer.read() 比逐行 readline() 快 5-10 倍,大数据量必用。


Java 输入输出模板

基础模板

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }

        // 处理...
        long result = solve(arr);
        System.out.println(result);
    }

    static long solve(int[] arr) {
        long sum = 0;
        for (int x : arr) sum += x;
        return sum;
    }
}

快速 IO(BufferedReader + StringTokenizer)

import java.io.*;
import java.util.*;

public class Main {
    static class FastReader {
        BufferedReader br;
        StringTokenizer st;

        FastReader() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() { return Integer.parseInt(next()); }
        long nextLong() { return Long.parseLong(next()); }
        double nextDouble() { return Double.parseDouble(next()); }
    }

    public static void main(String[] args) {
        FastReader fr = new FastReader();
        int n = fr.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) arr[i] = fr.nextInt();

        long result = solve(arr);
        System.out.println(result);
    }

    static long solve(int[] arr) {
        long sum = 0;
        for (int x : arr) sum += x;
        return sum;
    }
}

Scanner 在 10^5 数据量以上会非常慢,笔试中务必使用 BufferedReader。

快速输出(BufferedWriter)

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
bw.write(result + "\n");
bw.flush();

C++ 输入输出模板

基础模板

#include <bits/stdc++.h>
using namespace std;

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

    int n;
    cin >> n;
    vector<int> arr(n);
    for (int i = 0; i < n; i++) {
        cin >> arr[i];
    }

    long long sum = 0;
    for (int x : arr) sum += x;
    cout << sum << endl;

    return 0;
}

关键优化

ios::sync_with_stdio(false);  // 关闭 C 和 C++ 流的同步
cin.tie(nullptr);             // 解除 cin 和 cout 的绑定

这两行代码让 cin/cout 接近 scanf/printf 的速度。

大数据量读入

// 如果需要极致速度,使用 scanf/printf
int n;
scanf("%d", &n);
vector<int> arr(n);
for (int i = 0; i < n; i++) {
    scanf("%d", &arr[i]);
}
printf("%lld\n", result);

常见输入格式处理

矩阵输入

# n x m 矩阵
n, m = map(int, sys.stdin.readline().split())
matrix = []
for _ in range(n):
    row = list(map(int, sys.stdin.readline().split()))
    matrix.append(row)

图输入(边列表)

# n 个节点,m 条边
n, m = map(int, sys.stdin.readline().split())
graph = [[] for _ in range(n)]
for _ in range(m):
    u, v, w = map(int, sys.stdin.readline().split())
    graph[u].append((v, w))

字符串输入(含空格)

# 读取整行含空格的字符串
s = sys.stdin.readline().strip()

常见陷阱

陷阱说明解决方案
末尾空格输出末尾多了空格用 ' '.join(map(str, arr))
多组数据换行每组数据输出后空一行控制换行位置
数据范围超限int 存不下Java 用 long,Python 自动大整数
浮点精度小数输出要求 2 位System.out.printf("%.2f", val)
空行读取测试用例间有空行用 while 跳过空行
大数据 TLE算法正确但 IO 慢使用快速 IO 模板

笔试策略

时间分配(120 分钟 3 题为例)

阶段时间目标
读题 + 分析10 分钟理解所有题目,判断难度排序
第 1 题25 分钟简单题必拿下
第 2 题40 分钟medium 难度,核心逻辑
第 3 题35 分钟hard 难度,争取部分分
检查 + 提交10 分钟边界条件、样例验证

部分分策略

对于 hard 题,如果无法全 AC,可以尝试:

  • 暴力解法:小数据量能过,拿 30-50% 分
  • 特殊条件优化:如数据范围某个维度很小
  • 贪心/近似:不一定最优,但能过大部分测试点

平台差异速查

平台特点注意
牛客输入在控制台,可本地测试类名必须是 Main(Java)
赛码类似牛客注意多语言编译器版本
HackerRank函数模板已给函数内处理即可
Codeforces大数据、高并发必须用 fast IO
AtCoder时间限制较松Python 友好

练习建议

  1. 牛客网:“华为/字节/阿里笔试真题"专题
  2. Codeforces:Div 2 A/B 题练手,Div 2 C 题进阶
  3. AtCoder:Beginner Contest,适合入门
  4. 蓝桥杯:国内比赛,填空 + 编程混合

核心原则:ACM 模式不等于算法难,而是工程细节(输入输出、边界处理)决定成败。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页