目录
前言
A: 攻击次数
解题思路:
代码:
B: 最长字符串
解题思路:
代码:
C: LQ图形
解题思路:
代码:
D: 最多次数
解题思路:
代码:
E: A * B Problem
解题思路:
代码:
F: 园艺
编辑
解题思路:
代码:
G:书架还原
解题思路:
代码:
H: 异或和
解题思路:
代码:
结论:
前言
此次蓝桥杯共8道题(2道填空,6道编程)满分100。与去年的题相比难度降低了不少,第一道编程题简直送分,刚学的小白估计也会。我本人大一,刚学python不久,我只能说这次比赛中基本没用到什么算法,全是暴力,考前学习的DFS,BFS,二维前缀差分等等都没用上,虽然比赛中有的题我暴力也没做出来。当然,这套题想拿高分也不容易,面对巨大数据量,时间复杂度是个问题。
下面给大家分享一下满分题解,是我赛后重做,又综合各个大佬的题解做出的。以下代码在洛谷均可通过,现在蓝桥官网上还没更新,不知在蓝桥官网上测评如果。欢迎各位大佬对我的题解进行点评指正。
A: 攻击次数
解题思路:
这道题没什么难度,但有个小坑,正确结果为103,我估计会有不少人结果为104。这里需要注意的是在103回合后,血量已经小于0,但在下个while循环中,回合数仍+1,所以最后结果要-1。
代码:
n=2025
i=1
while n>0:atk = 5if i%2==1:atk+=15else:atk+=2if i%3==1:atk+=2if i%3==2:atk+=10if i%3==0:atk+=7n-=atki+=1
print(i-1)
B: 最长字符串
这道题有难度,比赛时没啥思路,50000个数据当时让电脑死机两回
解题思路:
想做对当然要先完全理解题目的啦。这里难点在于若s4是优美字符串,那么s3,s2,s1都必须是优美字符串。什么是字典序最小?简单来说就是如果相同长度,其字母在字母表中排位越靠前,字典序越小。例如 'abc'<'abd'。
- 为了方便遍历,要将50000个数据转换化成列表形式
- 先对列表按照长度排序,短的放在前面,因为长字符串是否符合需要短字符串进行辅助
- 建立一个seen集合,从短到长存储长度为1的字符串与不同长度的优美字符串
- 利用sorted()可将乱序字符串按字典序改成统一的顺序进行判断
- 利用for循环,从短到长依次判断。(txt文档可在博客顶部下载)
代码:
l= # 将txt中的所有数据复制到三引号内即可,此处省略
'''
tdasm
ciswmz
.
.
.
'''
l=l.split('\n')
l=list(set(l)) # 删除重复数据
l.sort(key = len)
seen = set()
ret = ''for i in l:if len(i) == 1:seen.add(i)else:ss = sorted(i[:-1])m=''.join(ss)if m in seen:ans = ''.join(sorted(i))seen.add(ans)if len(i) > len(ret): # 长度最长ret = ielif i < ret: # 字典序最小ret = iprint(ret)
C: LQ图形
解题思路:
超级简单,两个for循环
代码:
w,h,v=map(int,input().split())
for i in range(h):print('Q'*w)
for j in range(w):print('Q'*(v+w))
D: 最多次数
解题思路:
- 建立一个包含六种可能的列表
- 利用while循环切片,若在列表中计数加1
代码:
n=input()
num=0
i=0
seen1=['l','q','b']
seen2=['lqb','lbq','qlb','qbl','blq','bql']while i<=len(n)-3:if n[i] in seen1: # 减少不必要的切片操作ans=n[i:i+3]if ans in seen2:num+=1i+=3else:i+=1else:i+=1
print(num)
E: A * B Problem
有点难度,比赛时没啥思路,纯暴力的话应该可以通过40%--80%的数据,但要想全通过就要用到数论中约数个数与约数个数前缀和之间的计数关系
解题思路:
- 建立列表a,计算1--L 每一个数的约数个数
- 建立列表b,计算约数个数的前缀和
- 约数个数与约数个数前缀和乘积的累加
代码:
L=int(input())
ans=0
a=[0]*(L+1)
b=[0]*(L+1)for i in range(1,L+1):for j in range(i,L+1,i):a[j]+=1 #约数个数计数器 +1for i in range(1,L+1):b[i]=b[i-1]+a[i] #前缀和数组for i in range(1,L+1):ans+=a[i]*b[L-i] #统计答案
print(ans)
F: 园艺
解题思路:
- 这道题类似于求最长递增子序列,利用动态规划来做
- 建立一个dp数组,用来记录每一个以第i棵为结尾,d为间隔的棵树数据
- 遍历全部dp数组,找到最大值
代码:
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 # d为两树之间间隔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)
G:书架还原
我第一反应是利用两个for循环,虽然思路是对的,但时间复杂度太高,但只通过了30%的数据
解题思路:
- 要想操作次数最少,必须每一次操作都至少有一本书归放原处
- 从第一个为位置开始,定住一个位置,若此书理应不在此位置,进入while循环
- 在循环中,将此位置的书放回原位置,而原位置的书拿过来,再次进行while判断
代码:
n = int(input())
nums = list(map(int, input().split()))
count = 0for 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)
H: 异或和
涉及到双重求和,求两个数的异或和可以用“ ^ ” 内置函数,比赛时忘了这个东西可以求异或和
利用for循环嵌套可以暴力通过40%的数据,这就是8分啊,比赛时能得到这8分也很不错了。
暴力代码:(只能通过40%数据,仅供参考)
n = int(input())
nums = list(map(int, input().split()))
ans = 0for i in range(n):for j in range(i+1, n):x=j - ians += (nums[i] ^ nums[j]) * x
print(ans)
如果要的满分要涉及到位运算,二进制每一位对最后结果的贡献。
解题思路:
- 数据最大值的二进制有多少位,外循环就遍历多少次
- 内循环从最小位开始,拿出每个数据二进制的第i位,只有当两个数一个为0一个为1时,才会对最后结果产生贡献,因为按位异或的原理为同为0,异为1。
代码:
n = int(input())
a = list(map(int, input().split()))
ans = 0
bit = 1 # 权重初始为1s=bin(sorted(a)[-1])[2:]
for i in range(len(s)):dex0 = 0 # 当前位为0的下标和dex1 = 0 # 当前位为1的下标和count0 = 0 # 当前位为0的个数count1 = 0 # 当前位为1的个数for j in range(n):current = a[j]if (current >> i) & 1: # 判断此位是否为1index=j + 1 # 下标值=索引值+1ans += bit * (index * count0 - dex0) # 此位对最后结果的贡献dex1 += indexcount1 += 1else:index = j + 1ans += bit * (index * count1 - dex1)dex0 += indexcount0 += 1bit <<= 1 # 按位的权重*2
print(ans)
附:以题目所给[9,8,7,6]为例,计算第一次内循环的贡献为6。 ans=6+16+32+64=118
附:按位异或规则
结论:
总的来说,全用暴力也可以取得一个不错的成绩,想要高分还是有点难度的。本人是一个初学算法的大一小白,提供的代码和作图若有错误,欢迎各位大佬的点评指正,最后祝愿每一位参赛者都可以取得一个好成绩!!!