酷代码 AI
菜单
服务商

瑞士轮赛制模拟与 IndexError 防御性编程实战指南

你遇到的错误是: ``` IndexError: list index out of range at line 22: b = players[i + 1] ``` 并且多个测试点都报这个错(`cyj00.in`, `cyj01.in`, ...),说明 **你的 `players` 列表长度不是偶数**,或者 **循环中 `i+1` 超出了索引范围**。 --- ### 🔍 根本原因分析 你写了这行: ```python for i in range(0, n, 2): a = players[i] b = players[i + 1] # ← 这里出错! ``` ⚠️ **但 `n` 是选手总数,题目保证 `n` 是偶数吗?** ✅ 是的!题目明确说:“`n` 名编号为 `1..n` 的选手”,且每轮配对是 `1v2, 3v4, ..., (n−1)vn`,所以 **`n` 必为偶数** —— 这是瑞士轮前提。 那为什么还会越界? → 唯一可能是:**你在某轮更新 `players` 后,`len(players) != n`** 但你看代码: ```python players = [(new_scores[i], players[i][1], players[i][2]) for i in range(n)] ``` ✅ 这里 `range(n)` 是原始 `n`,不会变。所以 `len(players)` 始终是 `n`。 那问题出在哪?再看循环: ```python for i in range(0, n, 2): a = players[i] b = players[i + 1] ``` 如果 `n == 0`?不可能(输入保证 `n ≥ 2`)。 如果 `n == 2` → `i` 取值:`0` → `i+1 = 1` ✅ 如果 `n == 4` → `i`: `0,2` → `i+1`: `1,3` ✅ ✅ 看似没问题……但注意 Python 的 `range(stop)` 是 **不包含 `stop`** 的! 你写的是: ```python for i in range(0, n, 2): ``` 当 `n = 4` → `range(0,4,2)` → `i = 0, 2` → `i+1 = 1, 3` ✅ 当 `n = 2` → `range(0,2,2)` → `i = 0` → `i+1 = 1` ✅ 所以只要 `n` 是偶数,`i+1` 最大是 `n-1`,合法。 ❓那为什么报错? → **唯一合理解释:输入的 `n` 在某处被意外修改了,或读入失败导致 `n` 为奇数/0/负数。** 但更大概率是:**你没做输入容错,而某些测试点输入格式异常(如空行、少数据)导致 `scores` 或 `powers` 长度 ≠ `n`,进而 `players` 长度 ≠ `n`,后续 `range(0,n,2)` 中 `n` 是原始输入值,但 `players` 实际长度变小了!** 比如: ```python n, R, Q = map(int, input().split()) scores = list(map(int, input().split())) # 如果这行只读到 3 个数,但 n=4 → len(scores)=3 powers = list(map(int, input().split())) players = [(scores[i], i + 1, powers[i]) for i in range(n)] # ← i=3 时 scores[3] 报错! ``` 但你的报错是在 `b = players[i + 1]`,不是构造时,说明 `players` 构造成功了,长度是 `n`,但后续某轮中 `n` 被改了?不可能,`n` 是常量。 等等 —— 再看报错位置: ``` File "Main.py", line 22, in <module> b = players[i + 1] ``` 说明是**全局作用域**(不是函数内),且是第 22 行。你贴的代码中这一行在 `for _ in range(R):` 循环内部,但 traceback 显示它在 module level?可能你实际代码结构不同。 但无论如何,`IndexError` 只有一个原因: > `i + 1 >= len(players)` 所以我们要 **加防御性检查**,并**打印调试信息定位真实 `n` 和 `len(players)`**。 --- ### ✅ 正确、健壮、AC-ready 的 Python 代码(已修复所有隐患) ```python import sys def main(): data = sys.stdin.read().strip().split() if not data: return # 解析第一行:n, R, Q n = int(data[0]) R = int(data[1]) Q = int(data[2]) idx = 3 # 接下来 n 个初始分数 scores = list(map(int, data[idx:idx + n])) idx += n # 接下来 n 个实力值 powers = list(map(int, data[idx:idx + n])) idx += n # 构建 players: (score, id, power), id from 1 to n players = [] for i in range(n): players.append([scores[i], i + 1, powers[i]]) # 用 list 方便后续修改 score # 排序 key:分数降序,编号升序 def sort_key(p): return (-p[0], p[1]) for _ in range(R): # 排序 players.sort(key=sort_key) # 检查长度(防御) if len(players) != n or n % 2 != 0: # 理论不会进这里,但加一层保险 break # 新一轮比赛:两两配对 # 注意:必须用新列表存本轮得分变化,不能边遍历边改(否则影响后续配对逻辑) # 我们直接在 players[i][0] 上 +=1,但要确保不干扰当前轮排序(已排好序,安全) for i in range(0, n, 2): if i + 1 >= len(players): break # 安全兜底,防奇数长度 a = players[i] b = players[i + 1] if a[2] > b[2]: a[0] += 1 else: b[0] += 1 # 最终排序,输出第 Q 名的编号(Q 从 1 开始) players.sort(key=sort_key) print(players[Q - 1][1]) if __name__ == '__main__': main() ``` ### ✅ 关键修复点: | 问题 | 修复方式 | |------|-----------| | ❌ `tuple` 不可变,无法 `a[0] += 1` | 改用 `list`: `[score, id, power]`,支持原地修改 | | ❌ `players[i+1]` 越界 | 加 `if i + 1 >= len(players): break` 防御 | | ❌ 输入解析脆弱(空格/换行不稳) | 用 `sys.stdin.read().split()` 统一读取所有 token,健壮解析 | | ❌ 没处理 `n` 为奇数等异常(虽题设保证偶数,但防错有必要) | 加 `n % 2 != 0` 判断和 `break` | | ❌ 使用 `range(0,n,2)` 但 `n` 和 `len(players)` 不一致 | 全程用 `len(players)` 做边界,或严格保证构造正确 | --- ### 🧪 测试样例验证(快速过样例) 输入: ``` 4 4 2 7 6 6 7 10 5 20 15 ``` 输出:`1` ✅ --- ### 💡 Bonus:为什么 `cyj05.in` 报 `Forbidden system call:275`? - 错误码 `275` 通常是 `syscalls` 中的 `mmap` / `brk` / `mprotect` 等内存操作(常见于 `numpy`、`pypy`、或递归爆栈)。 - 你没用 numpy,但若用了 `sorted()` 大量次 + 大列表,Python 可能触发底层内存分配 syscall; - 更可能:你代码中有**无限递归 / 死循环**(比如 `R` 极大 + `n` 极大,`sort` 太慢导致超时,判题机强制 kill 并报 syscall 错误); - ✅ 本修复版用 `list.sort()`(Timsort,高效稳定),且无递归,可避免。 --- ######[AI写代码神器 | 2056点数解答 | 2026-03-20 12:15:30]

本站限时免费提问中
实用工具查看更多
Linux在线手册 [开发类]
Jquery在线手册 [开发类]
今日油价 [生活类]
图片互转base64 [开发类]
时间转换器 [开发类]