第一次参加蓝桥杯软件赛 Python 大学 B 组,面对 8 道题从紧张到渐入佳境,每道题都像一场小型闯关。以下是从试题 A 到 H 的完整解析,包含题目解读、代码实现、答案和算法总结,希望能帮大家理清思路,掌握核心方法。
敌人初始血量 2025,三个英雄每回合攻击规则:
纯模拟题,按回合循环计算总伤害,累减血量直到结束。注意回合从 1 开始,条件判断别搞反(如奇数回合是turn%2==1
)。
hp = 2025
turn = 0
while hp > 0:
turn += 1
dmg1 = 5
dmg2 = 15 if turn % 2 == 1 else 2
mod = turn % 3
dmg3 = 2 if mod == 1 else 10 if mod == 2 else 7
hp -= dmg1 + dmg2 + dmg3
print(turn) # 输出答案
103
if-else
处理不同情况。定义 “优美字符串”:长度 1 或前 n-1 个字符调整顺序后存在一个更短的优美字符串。从单词本中找最长的,字典序最小的。
with open('words.txt', 'r') as f:
words = [line.strip() for line in f]
# 按长度排序,同长度按字典序排序
words.sort(key=lambda x: (len(x), x))
max_len = 0
best_word = ''
# 记录每个长度的合法字符集合(排序后的字符串)
valid_sets = {1: set()} # 长度1的单词直接合法
for word in words:
n = len(word)
if n == 1:
valid_sets[1].add(''.join(sorted(word)))
if n > max_len:
max_len = n
best_word = word
else:
# 前n-1个字符排序后的字符串
prefix = ''.join(sorted(word[:-1]))
# 检查是否存在长度n-1的合法集合
if n-1 in valid_sets and prefix in valid_sets[n-1]:
if n not in valid_sets:
valid_sets[n] = set()
current_set = ''.join(sorted(word))
valid_sets[n].add(current_set)
if n > max_len or (n == max_len and word < best_word):
max_len = n
best_word = word
print(best_word) # 假设words.txt按题目示例输入,输出dbca
假设输入示例中的单词,答案为 dbca(实际需根据题目给定的 words.txt 计算,此处以示例逻辑推导)。
valid_sets
记录各长度的合法字符集合,逐步推导更长字符串的合法性。aabc
→aabc
排序后aabc
),方便快速判断是否存在前驱。画 L 型图形:竖线高 h、宽 w,横线高 w、宽 v+w,每个笔划由 'Q' 组成。
分两部分绘制:
w, h, v = map(int, input().split())
# 画竖线部分
for _ in range(h):
print('Q' * w)
# 画横线部分
for _ in range(w):
print('Q' * (v + w))
按输入输出样例,正确代码即可生成对应图形(无具体数值答案,需通过测试用例验证)。
统计字符串中能切割出最多的 “l、q、b” 各出现一次的子串(顺序不限),求最大次数。
每个子串需包含 1 个 l、1 个 q、1 个 b,因此答案是三个字符出现次数的最小值。
s = input().strip()
l = s.count('l')
q = s.count('q')
b = s.count('b')
print(min(l, q, b))
如样例输入 “lqbblqblqlxqb”,输出3。
求满足内积\(X_A*X_B + Y_A*Y_B ≤ L\)的正整数向量对\((X_A,Y_A,X_B,Y_B)\)的数量。
枚举\(X_A, Y_A\),计算内积上限后,求\(X_B, Y_B\)的可能取值。优化点:固定\(X_A, Y_A\),内积剩余值为\(L - X_A*X_B\),然后求\(Y_A*Y_B ≤ remaining\)的正整数解。
L = int(input())
count = 0
for xa in range(1, L + 1):
for ya in range(1, L + 1):
inner = xa * xb + ya * yb # 这里写错了,正确应为枚举xb和yb时,计算xa*xb + ya*yb ≤ L
# 正确写法:枚举xa, ya,然后计算对于固定的xa, ya,xb和yb的可能取值
max_xb_ya = L // xa if xa != 0 else L # 其实应重新组织循环:
for xa in range(1, L + 1):
for ya in range(1, L + 1):
remaining = L # 内积上限是remaining
# 对于当前xa, ya,求所有xb, yb≥1,使得 xa*xb + ya*yb ≤ remaining
# 固定xb,求yb的最大值:yb ≤ (remaining - xa*xb)/ya,当xa*xb >= remaining时,yb无解
for xb in range(1, L + 1):
xb_part = xa * xb
if xb_part >= remaining:
break # yb至少1,xb_part + ya*1 > remaining时,后面的xb更大,无需继续
max_yb = (remaining - xb_part) // ya
if max_yb >= 1:
count += max_yb
else:
# yb至少1,所以当(remaining - xb_part) < ya时,无解
pass
# 还要考虑xb=1时,ya*yb ≤ remaining - xa*1,即yb ≤ (remaining - xa)/ya
# 上面的循环有问题,正确做法是:枚举xa, ya, xb,计算yb的可能数量
count = 0
for xa in range(1, L + 1):
for ya in range(1, L + 1):
for xb in range(1, L + 1):
x_part = xa * xb
if x_part >= L:
break # xb再大,x_part超过L,yb至少1,总和必超
max_yb = (L - x_part) // ya
if max_yb >= 1:
count += max_yb
print(count)
样例输入 1
(L=2)输出 1
样例输入 2
(L=3)输出 5。
留下最多的树,满足等间隔(间隔 d≥1)且高度严格递增。求最大保留数量。
n = int(input())
h = list(map(int, input().split()))
max_len = 1 # 至少保留1棵树
for i in range(n):
for j in range(i+1, n):
d_pos = j - i # 间隔的位置差(步数)
current_len = 2
current_h = h[j]
pos = j + d_pos # 下一个位置
while pos < n:
if h[pos] > current_h:
current_len += 1
current_h = h[pos]
pos += d_pos
else:
break
max_len = max(max_len, current_len)
print(max_len)
样例输入 6 3 5 4 7 6 7,输出 3(选第 1、3、5 棵树,间隔 2,高度 3→4→6)。
通过交换任意两本书,求最少交换次数使排列有序。
利用循环节理论:每个循环节(如 3→1→2→3)需要长度 - 1 次交换。总次数 = 元素总数 n - 循环节数量。
n = int(input())
a = list(map(int, input().split()))
visited = [False] * (n + 1) # 元素编号1~n
cycle_count = 0
for i in range(n):
num = a[i]
if not visited[num]:
cycle_count += 1
# 遍历循环节
current = num
while not visited[current]:
visited[current] = True
current = a[current - 1] # a是0-based,元素是1-based,正确位置是current-1
print(n - cycle_count)
样例输入 3 3 1 2,输出 2(循环节长度 3,3-1=2 次交换)。
计算所有数对\((i,j)\)的\((a_i ⊕ a_j) * (j-i)\)之和,i 直接双重循环 O (n²) 会超时(n=1e5 时 1e10 次运算),需按二进制位拆分,计算每一位对总和的贡献。 样例输入 1 3 1 2 3 输出 8; 样例输入 2 4 9 8 7 6 输出 118。 第一次参赛难免紧张,但通过逐题拆解会发现,蓝桥杯的核心还是考察基础算法的灵活运用。从模拟到贪心,从枚举到动态规划,每道题都是对编程思维的打磨。记住:代码不在复杂,正确和高效才是关键!解读
代码
n = int(input())
a = list(map(int, input().split()))
ans = 0
for bit in range(20): # 最多2^20,处理0~19位
mask = 1 << bit
cnt0 = cnt1 = 0
sum0 = sum1 = 0 # sum0记录0的位置和,cnt0记录0的个数,同理sum1
for idx in range(n):
if a[idx] & mask:
ans += cnt0 * mask * (idx - sum0) # 0的个数乘以当前位权,乘以位置差之和
sum1 += idx
cnt1 += 1
else:
ans += cnt1 * mask * (sum1 - idx) # 1的个数乘以当前位权,乘以位置差之和
sum0 += idx
cnt0 += 1
print(ans)
答案
算法总结
总结:八道题的算法思想与核心考点
题号
题型
核心算法 / 思想
易错点 / 关键点
A
结果填空
模拟、条件分支
回合数从 1 开始,余数判断正确
B
结果填空
动态规划、集合排序
字符排序后检查前驱集合,字典序处理
C
程序设计
模拟绘图、规律拆解
横线宽度是 v+w,不是 v
D
程序设计
统计贪心
直接取三字符次数最小值,无需切割
E
程序设计
枚举优化、数学推导
三重循环优化,避免无效计算
F
程序设计
双重枚举、贪心
间隔是位置差,不是步数,递增条件严格
G
程序设计
循环节理论、图论
正确转换 1-based 元素与 0-based 索引
H
程序设计
位运算、逐位统计
按二进制位拆分,计算每一位的贡献
参赛建议