2025年第十六届蓝桥杯Python程序设计赛道B组
A. 攻击次数
题目描述
小蓝正在玩一个游戏,游戏中小蓝要控制自己的三个英雄来攻击一个敌人。敌人初始的血量为 2025。
小蓝的第一个英雄攻击力恒定,每回合攻击 5 的血量。
小蓝的第二个英雄拥有一些技能,奇数回合触发,攻击 15 的血量,偶数回合攻击 2 的血量。
小蓝的第三个英雄拥有一些道具,当回合数除以 3 的余数为 1 时攻击 2 的血量;当回合数除以 3 的余数为 2 时攻击 10 的血量;当回合数除以 3 的余数为 0 时攻击 7 的血量。
游戏从第 1 回合开始。不考虑敌人对小蓝英雄的攻击,敌人的血量也仅受攻击的影响。如果敌人的血量小于等于零,则游戏结束。
请问到第几回合游戏结束?
输入格式
无
输出格式
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只需要编写一个程序输出这个整数,输出多余的内容将无法得分。
输入输出样例
无
解题思路:
本题题目有歧义,根据多数用户理解我们修改了数据,目前洛谷数据判定为:3 个英雄只要能攻击就一起攻击,答案为103。如果 3 个英雄只能选择能攻击的中攻击最高的,答案为 181。
代码:
#每一回合可以攻击的英雄一起攻击
n = 1
num = 0
i = 1
while num < 2025:num += 5if i % 2 != 0:num += 15elif i % 2 == 0:num += 2if i % 3 == 1:num += 2elif i % 3 == 2:num += 10elif i % 3 == 0:num += 7i += 1
print (i - 1)
#每一回合只有一个英雄攻击
num = 2025
i = 1
n=1
while num > 0:if i % 2 != 0:num -= 15elif i % 3 == 2:num -= 10elif i % 3 == 0:num -= 7else:num -=5i += 1
print(i-1)
B. 最长字符串
题目描述
小蓝手里有一个单词本,上面记录了一些单词,保存在 words.txt 中,其中每一行包含一个仅有小写英文字母组成的单词。
小蓝想要找到一个最长的优美字符串。
一个长度为 n 的字符串 s=c1c2⋯cn 是优美字符串,必须满足 s 在单词本中,且满足以下两个条件之一:
- n=1;
- n>1,且存在一个优美字符串 s′,s′ 的长度为 n−1,s′ 的字符调整顺序后与 c1c2⋯cn−1 一致。
示例,假设 words.txt 文件中的单词如下:b、bc、cbd、dbca,那么:
- s1=b,长度 1,是优美字符串;
- s2=bc,s′=b 在单词本中出现过,并且是优美字符串,所以 s2 是优美字符串;
- s3=cbd,s′=bc 在单词本中出现过,并且是优美字符串,所以 s3 是优美字符串;
- s4=dbca,s′=cbd 在单词本中出现过,并且是优美字符串,所以 s4 是优美字符串;
现在请你帮助小蓝从单词本 words.txt 中找出长度最大的优美字符串,如果存在多个答案,优先使用字典序最小的那一个作为答案。
输入格式
输出格式
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个字符串,在提交答案时只需要编写一个程序输出这个字符串,输出多余的内容将无法得分。
输入输出样例
无
words.txt
import sys,time;t=time.time();a={};c={(0,)*26};d=set();sys.stdin=open('words.txt','r')
for i in range(50000):s=input();b=[0]*26for i in s[:-1]:b[ord(i)-97]+=1b=tuple(b)if b in a:a[b].append(s)else:a[b]=[s]
while c:e='~'for i in c:for j in a[i]:e=min(e,j);k=list(i);k[ord(j[-1])-97]+=1;k=tuple(k)if k in a:d.add(k)c,d=d,set()
print(e,time.time()-t)
C. LQ图形
题目描述
小蓝要为蓝桥画一个图形。由于小蓝的画图能力有限,他准备用大写字母 Q 画一个 L 形状的字符画。他希望 L 的粗细正好是 w 个字符宽,竖的笔划伸出 h 高(因此图形总共 h+w 高),横的笔划伸出 v 宽(因此图形总共 v+w 宽),要求每个笔划方方正正不能有多余内容。
例如,当 w=2,h=3,v=4 时,图形如下所示:
QQ
QQ
QQ
QQQQQQ
QQQQQQ
给定 w,h,v,请帮助小蓝画出这个图形。
输入格式
输入的第一行包含三个正整数 w,h,v,相邻整数之间使用一个空格分隔。
输出格式
输出若干行,表示对应的图形。
输入输出样例
输入 #1复制
3 4 5
输出 #1复制
QQQ QQQ QQQ QQQ QQQQQQQQ QQQQQQQQ QQQQQQQQ
说明/提示
评测用例规模与约定
对于 30% 的评测用例,w=1,1≤h,v≤20;
对于 60% 的评测用例,1≤w,h,v≤20;
对于所有评测用例,1≤w,h,v≤100。
解题思路
q=input().strip()
w,h,v=[eval(x) for x in q.split(" ")]
b=a=""
for i in range(w):b+="Q"
for i in range(w+v):a+="Q"
for i in range(h):print(b)
for i in range(w):print(a)
D.最多次数
题目描述
小蓝有一个字符串 s,他特别喜欢由以下三个字符组成的单词:l,q,b,任意顺序都可以,一共有 6 种可能:lqb、lbq、qlb、qbl、blq、bql。
现在他想从 s 中,尽可能切割出多个他喜欢的单词,请问最多能切割出多少个?单词指的是由若干个连续的字符组成的子字符串。
输入格式
输入一行包含一个字符串 s。
输出格式
输出一行包含一个整数表示答案。
输入输出样例
输入 #1复制
lqbblqblqlxqb
输出 #1复制
3
说明/提示
评测用例规模与约定
- 对于 20% 的评测用例,1≤∣s∣≤10;
- 对于 40% 的评测用例,1≤∣s∣≤20;
- 对于 60% 的评测用例,1≤∣s∣≤100;
- 对于 70% 的评测用例,1≤∣s∣≤103;
- 对于 80% 的评测用例,1≤∣s∣≤104;
- 对于所有评测用例,1≤∣s∣≤105,s 中只包含小写字母。
解题思路:
s = input().strip()
k = ["lqb", "lbq", "qlb", "qbl", "blq", "bql"]
n = len(s)
ans=0
i=0
while i < (n-2):sub = s[i:i+3]if sub in k:ans += 1i += 3else:i += 1
print(ans)
E. A * B Problem
题目描述
设有两个二维向量 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。
输入格式
输入的第一行包含一个正整数 L,表示题目描述中的限制条件。
输出格式
输出一行包含一个整数表示答案。
输入输出样例
输入 #1复制
2
输出 #1复制
1
输入 #2复制
3
输出 #2复制
5
说明/提示
评测用例规模与约定
- 对于 40% 的评测用例,L≤50;
- 对于 80% 的评测用例,L≤5000;
- 对于所有评测用例,1≤L≤220。
解题思路:
n=int(input())
ans=0
a=[0]*1048577 #1048577=2^20+1
b=[0]*1048577
for i in range(1,n+1):for j in range(i,n+1,i):a[j]=a[j]+1 #计数器 +1
for i in range(1,n+1):b[i]=b[i-1]+a[i] #前缀和数组
for i in range(1,n+1):ans=ans+a[i]*b[n-i] #统计答案
print(ans)
F. 园艺
题目描述
小蓝从左到右种了 n 棵小树,第 i 棵树的高度为 hi,相邻树的间隔相同。小蓝想挪走一些树使得剩下的树等间隔分布,且从左到右高度逐渐上升(相邻两棵树高度满足右边的比左边的高),小蓝想知道最多能留下多少棵树。
输入格式
输入的第一行包含一个正整数 n。
第二行包含 n 个正整数 h1,h2,⋯,hn,相邻整数之间使用一个空格分隔。
输出格式
输出一行包含一个整数表示答案。
输入输出样例
输入 #1复制
6 3 5 4 7 6 7
输出 #1复制
3
说明/提示
样例说明
留下第 1、3、5 棵树,它们等间隔且从左到右高度逐渐上升。
评测用例规模与约定
- 对于 30% 的评测用例,1≤n≤500;
- 对于 60% 的评测用例,1≤n≤3000;
- 对于所有评测用例,1≤n≤5000,0<hi<106。
解题思路:
n = int(input())
h = list(map(int, input().split()))
max_len = 0
for step in range(1, n):pre = float('-inf')cur_len = 0for i in range(0, n, step):if h[i] > pre:pre = h[i]cur_len += 1max_len = max(max_len, cur_len)
print(max_len)
G. 书架还原
题目描述
在一个偏远的图书馆里,有个书架上放着 n 本书,每本书上都标有一个从 1 到 n 的唯一编号。
按照规矩,这些书应该按编号从小到大依次排列:1 号书位于最左端,2 号书紧随其后,以此类推,直到 n 号书在最右端。这样的顺序不仅看起来整齐,也方便读者快速找到想借的书。
可昨天店里人来人往,借书还书忙得不可开交,书架上的顺序出现了错乱。现在,书架上的书变成了 a=(a1,a2,…,an),其中 ai 表示第 i 个位置上的书编号。
管理员决定动手整理书架,但时间有限,他希望用最少的操作把书的顺序恢复到正确的排列。每次操作,他可以挑选书架上任意两本书,交换它们的位置。例如,如果当前排列是 (3,1,2),他可以交换第 1 本和第 2 本,得到 (1,3,2),再交换第 2 本和第 3 本,得到 (1,2,3)。
你的任务是帮助管理员计算,最少需要进行多少次操作,才能让书架上的书的编号排列变为 (1,2,…,n)。
输入格式
输入的第一行包含一个正整数 n,表示书架上书的总数。
第二行包含 n 个正整数 a1,a2,…,an,相邻整数之间使用一个空格分隔,依次表示当前书架上每本书的编号。a1,a2,…,an 是一个 1 到 n 的排列。
输出格式
输出一行包含一个整数表示答案,即将书架上的书恢复到正确排列所需的最少操作次数。
输入输出样例
输入 #1复制
3 3 1 2
输出 #1复制
2
说明/提示
评测用例规模与约定
- 对于 30% 的评测用例,1≤n≤103,1≤ai≤n,a1,a2,…,an 各不相同;
- 对于所有评测用例,1≤n≤106,1≤ai≤n,a1,a2,…,an 各不相同。
解题思路:
import array
ag = array.array('i',10**6 + 5)
n = int(input())
w = list(map(int, input().split()))
w = + w
max_size = n + 2
for i in range(1, n + 1):ag[w[i]] = i
ans = 0
for i in range(1, n + 1):if w[i] != i:val = w[i]pos = ag[i]ag[val] = pos w[i], w[pos] = w[pos], w[i]ag[i] = ians += 1
print(ans)
H.异或求和
题目描述
小蓝有 n 个数 ai,他想知道这 n 个数中的所有数对下标的差值乘上它们的异或之后,得到的结果的和是多少。
也就是说,小蓝想要得到
i=1∑nj=i+1∑n(ai⊕aj)×(j−i)
的值,其中 ⊕ 表示按位异或。
输入格式
输入的第一行包含一个正整数 n。
第二行包含 n 个正整数 a1,a2,⋯,an,相邻整数之间使用一个空格分隔。
输出格式
输出一行包含一个整数表示答案。
输入输出样例
输入 #1复制
3 1 2 3
输出 #1复制
8
输入 #2复制
4 9 8 7 6
输出 #2复制
118
说明/提示
评测用例规模与约定
- 对于 40% 的评测用例,n≤5000;
- 对于所有评测用例,1≤n≤105,1≤ai≤220。
解题思路:
import sysdef main():n = int(sys.stdin.readline())a = list(map(int, sys.stdin.readline().split()))ans = 0bit = 1for i in range(21):p0 = 0p1 = 0sum0 = 0sum1 = 0for j in range(n):current = a[j]if (current >> i) & 1:ans += bit * ((j + 1) * sum0 - p0)p1 += j + 1sum1 += 1else:ans += bit * ((j + 1) * sum1 - p1)p0 += j + 1sum0 += 1bit <<= 1print(ans)if __name__ == "__main__":main()