
从刚学 Python 那会儿到现在我在洛谷上陆陆续续刷了不少题。P5704 是我印象很深的一道入门题不是因为难而是因为它几乎集合了所有新手第一次提交时会踩到的坑读入、字符串处理、输出、边界情况一个不落。很多朋友觉得这题简单到不屑于动手结果一到提交页面就是 0 分反而卡了半小时。我打算把这题从头到尾拆开讲一遍包括最直观的解法、背后涉及的 ASCII 原理、常见的翻车点以及怎么顺着这道题把洛谷入门题单刷得更顺。内容主要面向刚装好 Python、准备用刷题网站练手的同学也适合想给身边人讲懂这道题的朋友参考。1. 先弄明白 P5704 到底让你干什么1.1 题目原文与样例P5704 在洛谷的完整名字是【深基2.例6】字母转换。题目描述短得不能再短输入一个小写字母输出其对应的大写字母。保证输入一定是小写字母。没有复杂的多组数据没有任何刁钻要求就是单个字符的转换。输入格式是一行一个小写字母输出格式是一行一个大写字母。样例输入是 a样例输出是 A。就这么多信息没有多余的话也没有隐藏的陷阱。这种题放在其他 OJ 上可能被当成签到题里的签到题但洛谷把它放在深基题单的第二部分位置很讲究。它要的不是你会不会做而是你有没有把输入-处理-输出这条最底层的流水线走通。1.2 深基题单的定位深基全称是深入基础是洛谷专门给零基础选手设计的一条题单线从最简单的输入输出开始一步一步往数据结构、算法那边引。P5704 排在这一节的第 6 个例题前面的题刚教完变量和基本运算到这里就开始碰字符串了。所以别小看这个例6的身份。它是在告诉你字符串操作的大门从这里打开。后面你会遇到大小写转换出现在密码学、文本处理、字符串匹配等各种场景里P5704 就是那个最早的种子。1.3 表面简单实际考了三件事我刷题到现在最大的感受是简单题往往不是考你智商而是考你三个基本功会不会正确读入一行数据并理解读进来的东西到底是什么类型会不会用合适的工具把字符从一种形式变成另一种形式会不会把结果按题目要求的格式输出这三件事每一件单独拿出来都简单到不值一提但合在一起就是 0 分和满分之间的差距。很多人第一次提交莫名其妙的报错排查到最后发现就是一个换行符或者一个多余空格的问题。P5704 很适合当这个体检题看看你到底有没有把这些基本功焊死在肌肉记忆里。2. 最简单的解法让 Python 内置方法干活2.1 三行代码跑通先给出最朴素、最不容易出错的版本c input() result c.upper() print(result)提交到洛谷语言选 Python 3直接 AC。这个版本的好处是每一步都拆开了逻辑清晰。input() 把 a 读进变量 c然后调用字符串方法 upper() 得到 A最后 print 输出。字符串在 Python 里是不可变对象这一点新手经常忽略。upper() 并不是在原来的字符串上改而是生成一个全新的字符串返回。原变量 c 还是 aresult 才是 A。理解了这个后面学 replace、split、strip 这些方法时就不会困惑为什么我调用了方法原字符串没变。2.2 一行版与它的道理等熟悉了之后我更喜欢写成一行print(input().upper())这行代码的执行顺序是从内往外先 input() 读入再 upper() 转换最后 print 输出。一行版写起来爽但我不建议新手一上来就追求这种写法。你至少要能清楚说出每个括号的作用否则哪天括号套三层你连自己写的代码都读不懂。实测下来这题用 upper() 是代码量和出错率的最优解。输入只有一个字符时间复杂度可以忽略不计内置方法是 C 语言实现的速度比你自己写循环遍历快了不止一个量级。2.3 本地怎么跑、怎么验证刷题不能只在网页上盲交这是我一直强调的习惯。先在本地建一个文件比如 p5704.py把代码写进去然后在终端里执行python p5704.py手动输入 a回车看到输出 A再把输入换成 z看是不是输出 Z。两个用例都过了再粘贴到洛谷的提交框。很多人嫌这一步麻烦直接在网页上写、网页上跑出了问题就干瞪眼。本地跑的好处是你能自由控制输入想看什么用例就看什么用例。后面做到复杂题目时这个习惯几乎是救命稻草——因为你可以在本地反复测试极端数据而不是每次修改都要重新提交一遍等判题结果。3. 藏在三行代码里的输入输出细节3.1 input() 到底读到了什么input() 在 Python 3 中读的是一行并且会把这行末尾的换行符剥掉再返回返回类型是字符串。这个设计非常贴心但正因为太贴心很多人反而忽略了它做了什么。对比一下就明白了。如果用 sys.stdin.read() 直接读import sys data sys.stdin.read() print(repr(data)) # 输入 a 后得到 a\n看到那个 \n 了吗repr() 会把它原形毕露地显示出来。如果你用 sys.stdin.readline().upper()读进来的其实是 a\nupper() 之后变成 A\n再交给 print 又附加一个换行最终输出变成 A 后面跟两个换行。大部分 OJ 对末尾多余空白是宽容的但某些系统严格比对字符流就会出现莫名其妙的 Presentation Error 或者 Wrong Answer。这就是我为什么推荐用 input()。它把末尾换行这个问题从源头上解决了你不需要自己 remove。3.2 输出的换行是 print 帮你加的print() 默认会在字符串末尾补一个换行符所以 print(A) 实际输出的是 A\n。这是绝大多数判题系统期望的格式一行一个结果。与之对应的是 sys.stdout.write(A)它不会加换行。如果你有两个结果要分两行输出用 write 就得自己拼 \n写起来很啰嗦。我个人刷题基本只用 print只有碰到输出格式极其刁钻、需要精确控制空格和换行的题目才会上 write。这里有个新手常有的疑问我多输出一个换行会不会被判错在洛谷通常不会因为判题器会忽略末尾的空白字符。但别依赖这种宽容按题目要求来才是最稳妥的。3.3 strip() 是不是必须的input() 已经把行尾换行去掉了那还有必要再 strip() 吗看数据。这题保证输入就是一个小写字母前后没有多余空格所以不 strip 也能过。但如果测试数据的字母前后真有空格比如 a 直接 upper() 会得到 A 和标准答案 A 不一致就会被判错。为了写得更防御性可以这样c input().strip() print(c.upper())strip() 会去掉字符串首尾的空白字符包括空格、制表符、换行。多写这一步不扣分遇到不规范数据还能救命。我建议入门阶段就把这个习惯养成但心里要清楚input() 去换行是规定动作strip() 去首尾空白是附加保险两者不是一回事。4. 不用 upper() 也能过手摸 ASCII 码4.1 英文字母在 ASCII 表里的位置有些人会觉得只用 upper() 太没意思想搞清楚底层发生了什么。那就得认识 ASCII 码。小写字母 a 的 ASCII 值是 97z 是 122大写字母 A 是 65Z 是 90。同一个字母的大小写之间恰好相差 32。字符azAZASCII 值971226590记住两个锚点就行a 是 97A 是 65。剩下的字母按字母表顺序递增所以 b 是 98B 是 66依次类推。这张表不用死记需要的时候查一下用多了自然就记住了。4.2 ord() 和 chr() 组合的写法既然大小写差 32那转换逻辑就很简单小写字母的 ASCII 值减去 32再转回字符。c input() upper_c chr(ord(c) - 32) print(upper_c)ord() 把字符转成整数chr() 把整数转回字符。ord(a) 得到 97减 32 得到 65chr(65) 得到 A。这条链路每一步都很清楚算得明明白白。这个写法的价值不在于比 upper() 快而在于它逼你思考字符的本质是什么。在计算机里字符就是一个数字只是通过编码表显示成我们认识的样子。想明白这一点后面遇到凯撒加密、字母偏移、Excel 列号转换这类题ord 和 chr 的组合就是万能钥匙。4.3 为什么我不推荐这道题用 swapcase()Python 还有个方法叫 swapcase()作用是大小写互换。理论上输入小写、输出大写拿 swapcase() 也能过print(input().swapcase())但我真心不推荐在这题里用。swapcase() 的语义是翻转大小写输入大写会变小写输入小写会变大写。这道题恰好只需要小写转大写所以它能蒙对。但是解法与题意必须严格对应这是刷题的基本原则。upper() 表达的就是转大写和题目要求一字不差swapcase() 是翻转跟题意隔了一层属于碰巧能用不是正确表达。今天这题你用 swapcase() 蒙过了明天遇到输入一串混合大小写字母把其中的小写转大写、大写保持不变你就会因为偷懒吃大亏。4.4 两种解法的适用边界那么 upper() 和 ord/chr 到底怎么选我的经验是一看题意二看场景。如果题目明确说小写转大写优先用 upper()语义清晰、代码简洁。如果题目涉及字母的循环移位比如把 a 变 b、z 变 a或者大小写互换upper() 就不够用了必须上 ord/chr 或者 swapcase()。如果题目要求处理的是数字字符那又是另一套逻辑用 int() 或者 ASCII 差值都行。这道题最好的练法是把两种写法都提交一遍看看 AC 结果一样心态完全不一样。你会直观感受到库函数方便原理扎实两条路都能到罗马但走法不同沿途看到的风景不同。5. 提交翻车实录新手最容易卡住的地方5.1 最常见的几个 0 分原因我把自己当年以及身边新手踩过的坑整理成了下面这张表每一行都是真实发生过的错误写法问题在哪正确做法print(A)把样例答案写死了输入 b 还是输出 A从 input() 读入再转换print(input().upper() )结果多了一个空格和标准答案不匹配别手动加多余空格c input(); print(c.lower())大小写搞反了完全没读懂题目用 upper()c int(input())输入是字母int(a) 直接抛 ValueError字符不要转 int直接用字符串方法代码里混着 C 的 cin/cout语言没选对或语法混杂Python 就用 Python 语法表里第四行值得单独说。很多入门教程讲输入输出时爱拿数字举例新手就形成了凡输入必 int()的惯性思维。P5704 输入的是字母int(a) 会直接报错程序崩溃判题结果就是 Runtime Error。所以拿到题目第一件事永远是看数据而不是套模板。5.2 拿到 80 分或部分分时该怎么排查热词里有人问洛谷 p10472 为什么只拿 80 分虽然具体题目不同但规律是通用的判题返回部分分说明你过了样例和一些常规测试点但某个隐藏测试点挂了。隐藏点通常就藏在边界条件里。以 P5704 为例如果题目稍微扩展一下可能出现这些边界输入不是小写字母而是大写字母或者数字输入前后有空格输入为空字符串输入包含多个字符你自己在心里过一遍这些情况手动构造用例在本地测一测就能把潜在的坑踩平。我曾经做一道题第一次提交 80 分排查半天发现是读整行时把多余的换行也当成内容输出出去了。从那以后无论题目多简单我提交前都在本地测三个用例正常用例、边界用例、异常用例。5.3 提交环境和语言版本相关的坑洛谷运行的是 Python 3千万别写 Python 2 的语法。常见的坑包括把 print 当语句用也就是不加括号直接 print A这在 Python 3 里直接语法错误还有用 raw_input()这是 Python 2 的老函数Python 3 里根本不存在。如果你电脑里装了多个 Python 版本运行 p5704.py 之前先敲一句 python --version 确认当前指向哪个版本别让 python 命令悄悄指向旧版代码跑起来行为完全不一样。另外洛谷提交页面的语言下拉框一定要选对别在 Python 环境跑通了代码提交时却手滑选了 C然后看着一片编译错误干着急。这种低级失误最浪费心情提交前扫一眼语言选项成本几乎为零。6. 从 P5704 出发聊聊洛谷入门题单怎么刷6.1 刷题前的环境准备如果你还没装 Python去官网下载对应系统的安装包安装到倒数第二步时记得勾选Add Python to PATH否则在终端里敲 python 会提示找不到命令。装完打开终端输入python --version能看到版本号环境就算成了。编辑器我推荐 VS Code装好官方 Python 扩展之后打开一个 .py 文件按 F5 键就能直接运行能看到输出、能打断点对新手非常友好。洛谷的网页提交和本地环境并不冲突。我的工作流一直是本地写代码本地测用例然后再去网页提交。这样既练了真正的编码能力又不会因为频繁提交被判题的等待时间拖慢节奏。6.2 同一批入门题可以连着做P5704 属于【深基2】这一节配套的题非常适合连着刷每一道都能补一个知识点P5703 苹果采购输入两个整数输出乘积练 int() 和算术运算P5705 数字反转把一个三位数反转练字符串切片的灵活用法P5706 再分肥宅水小数除法加格式化输出练保留几位小数P5708 求直角三角形面积开平方和格式化练 math.sqrt 和输出控制这几道题的共同特点是不涉及复杂算法但每一道都逼你掌握一个 Python 常用功能。我的建议是每道题先自己写卡住了再看题解看完之后关掉题解凭记忆重新写一遍。连续搞三五道之后input、print、类型转换、字符串方法这些东西才是真正长在你身上了而不是眼睛会了手不会。6.3 刷题心态别在简单题上追求炫技经常有人在入门题的题解区写一堆花哨解法列表推导式、lambda、一行代码骚操作看着很酷但对初学者没啥用。P5704 你只要能讲清楚读入-转换-输出这三步就是满分答案。等基础稳了再去研究函数式写法、性能优化也不迟。我刷题到现在一直坚持一个原则先有能跑的朴素解法再谈优化。朴素解法帮你理解问题本质优化解法帮你理解语言特性顺序一旦反了很容易把简单问题复杂化最后连朴素解法都写不利索。最后分享一个小习惯刷这种入门题时把不同解法整理到自己的笔记里标注每种写法用到的知识点。比如 P5704 就记两条upper() 对应字符串内置方法ord/chr 对应 ASCII 转换。等刷到一百道题再翻开笔记你会发现自己已经把 Python 的核心语法覆盖了个七七八八而且每一条都有真实题目做对应比干啃语法书记得牢得多。