第一题
P12170 [蓝桥杯 2025 省 Python B] 攻击次数 - 洛谷
题目描述
小蓝正在玩一个游戏,游戏中小蓝要控制自己的三个英雄来攻击一个敌人。敌人初始的血量为 2025。
小蓝的第一个英雄攻击力恒定,每回合攻击 5 的血量。
小蓝的第二个英雄拥有一些技能,奇数回合触发,攻击 15 的血量,偶数回合攻击 2 的血量。
小蓝的第三个英雄拥有一些道具,当回合数除以 3 的余数为 1 时攻击 2 的血量;当回合数除以 3 的余数为 2 时攻击 10 的血量;当回合数除以 3 的余数为 0 时攻击 7 的血量。
游戏从第 1 回合开始。不考虑敌人对小蓝英雄的攻击,敌人的血量也仅受攻击的影响。如果敌人的血量小于等于零,则游戏结束。
请问到第几回合游戏结束?
代码示例
blood_volume = 2025
turns = 1
while blood_volume > 0:
blood_volume -= 5
if turns % 2 == 1:
blood_volume -= 15
elif turns % 2 == 0:
blood_volume -= 2
if turns % 3 == 1:
blood_volume -= 2
elif turns % 3 == 2:
blood_volume -= 10
elif turns % 3 == 0:
blood_volume -= 7
print(turns, blood_volume)
turns += 1
可以看到第 102 回合敌人血量大于 0 而第 103 回合敌人血量小于 0,所以正确答案为 103。
为什么答案是 103 而不是 104?
注意 turns 的更新位置。如果将 turns 错误写在前面,那就应该检查一下答案,发现是从 2 开始计数。
第二题
P12171 [蓝桥杯 2025 省 Python B] 最长字符串 - 洛谷
题目描述
小蓝手里有一个单词本,上面记录了一些单词,保存在 words.txt 中,其中每一行包含一个仅有小写英文字母组成的单词。
小蓝想要找到一个最长的优美字符串。
一个长度为 n 的字符串 s=c1c2⋯cn 是优美字符串,必须满足 s 在单词本中,且满足以下两个条件之一:n=1;n>1,且存在一个优美字符串 s′,s′的长度为 n−1,s′的字符调整顺序后与 c1c2⋯cn−1 一致。
现在请你帮助小蓝从单词本 words.txt 中找出长度最大的优美字符串,如果存在多个答案,优先使用字典序最小的那一个作为答案。
代码示例
with open('words.txt', 'r', encoding='utf-8') as f:
l = f.read()
l1 = l.strip().split('\n')
l1 = list(set(l1)) # 去重
l1.sort(key=len) # 按长度排序
seen = set() # 存储排序后的字符串
maxlen = ""
for i in l1:
if len(i) == 1:
seen.add(i)
else:
prefix_sorted = ''.join(sorted(i[:-1]))
if prefix_sorted in seen:
current_sorted = ''.join(sorted(i))
seen.add(current_sorted)
if len(i) > len(maxlen):
maxlen = i
elif len(i) == len(maxlen) and i < maxlen:
maxlen = i
print(maxlen)
为什么必须按长度排序?
- 优美字符串的定义:长度为 1 的字符串一定是优美的。长度 >1 的字符串,必须其前缀的某种排列已经存在于
seen中。 - 必须先处理短字符串:确保长字符串的前缀已经被处理过,否则无法正确判断。
- 例如
'abc'是优美字符串(因为'ab'是它的前缀,且'ab'是优美字符串)。但如果'abc'先被处理,其前缀不在集合中,不会被识别。
第三题
P12172 [蓝桥杯 2025 省 Python B] LQ 图形 - 洛谷
题目描述
小蓝要为蓝桥画一个图形。由于小蓝的画图能力有限,他准备用大写字母 Q 画一个 L 形状的字符画。他希望 L 的粗细正好是 w 个字符宽,竖的笔划伸出 h 高(因此图形总共 h+w 高),横的笔划伸出 v 宽(因此图形总共 v+w 宽),要求每个笔划方方正正不能有多余内容。
给定 w,h,v,请帮助小蓝画出这个图形。
代码示例
w, h, v = map(int, input().split())
for i in range(h):
print("Q" * w)
for j in range(w):
print("Q" * (v + w))
易错点总结
- 字符串表示:必须用引号括起字符'Q',否则 Python 会将其视为变量。
- 横笔划宽度计算:容易忘记横笔划需要包含竖笔划的宽度 (w),正确的宽度应该是 v + w。
- 输出顺序:必须先输出竖笔划 (h 行),再输出横笔划 (w 行)。
- 输入处理:使用 map+split,输入必须是三个用空格分隔的整数。
第四题
题目描述
小蓝有一个字符串 s,他特别喜欢由以下三个字符组成的单词:l,q,b,任意顺序都可以,一共有 6 种可能:lqb、lbq、qlb、qbl、blq、bql。
现在他想从 s 中,尽可能切割出多个他喜欢的单词,请问最多能切割出多少个?单词指的是由若干个连续的字符组成的子字符串。
代码示例
s = input().strip()
count = 0
i = 0
n = len(s)
while i <= n - 3:
if {s[i], s[i+1], s[i+2]} == {'l', 'q', 'b'}:
count += 1
i += 3
else:
i += 1
print(count)
逻辑问题
- 当
i接近字符串末尾时,i+3可能超出字符串长度,导致 IndexError。 - 每次匹配成功后,应该跳过这三个字符(即
i += 3),否则会重复计算。
第五题
设有两个二维向量 A(XA,YA),B(XB,YB)。给定 L,求 (XA,YA),(XB,YB) 有多少种不同的取值,使得:XA,YA,XB,YB 均为正整数;A·B≤L,其中 A·B 表示 A,B 的内积,即 XA·XB+YA·YB。
1. 暴力枚举法
L = int(input())
count = 0
for xa in range(1, L + 1):
for ya in range(1, L + 1):
for xb in range(1, L + 1):
for yb in range(1, L + 1):
if xa * xb + ya * yb <= L:
count += 1
print(count)
2. 优化枚举
L = int(input())
count = 0
for xa in range(1, L + 1):
for ya in range(1, L + 1):
max_sum = L
for xb in range(1, L + 1):
remain = max_sum - xa * xb
if remain <= 0:
break
max_yb = remain // ya
if max_yb >= 1:
count += max_yb
print(count)
3. 数学优化(数论 + 前缀和)
L = int(input())
ans = 0
a = [0] * (L + 1) # a[s] 表示 s 的约数个数
b = [0] * (L + 1) # b[t] 表示前缀和
# 步骤 1:计算每个数的约数个数
for i in range(1, L + 1):
for j in range(i, L + 1, i):
a[j] += 1
# 步骤 2:计算约数个数的前缀和
for i in range(1, L + 1):
b[i] = b[i-1] + a[i]
# 步骤 3:统计答案
for i in range(1, L + 1):
ans += a[i] * b[L-i]
print(ans)
第六题
P12175 [蓝桥杯 2025 省 Python B] 园艺 - 洛谷
题目描述
小蓝从左到右种了 n 棵小树,第 i 棵树的高度为 hi,相邻树的间隔相同。小蓝想挪走一些树使得剩下的树等间隔分布,且从左到右高度逐渐上升(相邻两棵树高度满足右边的比左边的高),小蓝想知道最多能留下多少棵树。
1. 暴力枚举法
n = int(input())
h = list(map(int, input().split()))
if n == 0:
print(0)
max_len = 1
for i in range(n):
for d in range(1, n):
current_pos = i
current_len = 1
prev_height = h[current_pos]
next_pos = current_pos + d
while next_pos < n:
if h[next_pos] > prev_height:
current_len += 1
prev_height = h[next_pos]
current_pos = next_pos
next_pos = current_pos + d
else:
break
if current_len >= 2:
if current_len > max_len:
max_len = current_len
print(max_len)
2. 动态规划 (O(n²))
n = int(input())
a = list(map(int, input().split()))
dp = [[1] * (n + 1) for i in range(n)]
for i in range(n):
for j in range(i):
if a[i] > a[j]:
d = i - j
dp[i][d] = max(dp[i][d], dp[j][d] + 1)
ans = 0
for row in dp:
if max(row) > ans:
ans = max(row)
print(ans)
第七题
P12176 [蓝桥杯 2025 省 Python B] 书架还原 - 洛谷
题目描述
在一个偏远的图书馆里,有个书架上放着 n 本书,每本书上都标有一个从 1 到 n 的唯一编号。按照规矩,这些书应该按编号从小到大依次排列。可昨天店里人来人往,借书还书忙得不可开交,书架上的顺序出现了错乱。现在,书架上的书变成了 a=(a1,a2,…,an),其中 ai 表示第 i 个位置上的书编号。管理员决定动手整理书架,但时间有限,他希望用最少的操作把书的顺序恢复到正确的排列。每次操作,他可以挑选书架上任意两本书,交换它们的位置。
你的任务是帮助管理员计算,最少需要进行多少次操作,才能让书架上的书的编号排列变为 (1,2,…,n)。
代码 1(使用 index() 查找目标位置)
n = int(input())
a = list(map(int, input().split()))
count = 0
for i in range(n):
while a[i] != i + 1:
j = a.index(i + 1)
a[i], a[j] = a[j], a[i]
count += 1
print(count)
代码 2(直接计算目标位置)
n = int(input())
nums = list(map(int, input().split()))
count = 0
for i in range(n):
while i != nums[i] - 1:
ans = nums[i]
nums[i] = nums[ans - 1]
nums[ans - 1] = ans
count += 1
print(count)
| 代码 1(index()) | 代码 2(直接计算) |
|---|---|
| 使用 index() 查找目标位置 | 直接通过值计算目标位置 |
| 时间复杂度 O(n²) | 时间复杂度 O(n) |
第八题
P12177 [蓝桥杯 2025 省 Python B] 异或和 - 洛谷
题目描述
对于每对数 (nums[i], nums[j]),计算它们的异或值 nums[i] ^ nums[j]。
代码示例
n = int(input())
nums = list(map(int, input().split()))
ans = 0
for i in range(n):
for j in range(i+1, n):
x = j - i
ans += (nums[i] ^ nums[j]) * x
print(ans)
注:如果只想拿'省一'的话,考试时候写能写对这样的暴力算法就很厉害。
(此句已根据清理规则移除)

