第二次参加蓝桥杯竞赛了,欢迎各位同学来一起交流~ 如果发现我的代码有什么问题的话,敬请指正(抱拳
PS:只记得每个题目的问题本质了,题目原文是怎么描述已经忘得差不多了。
原问题:从1到2020中这些数字中有多少个2(注意:不是问多少个数字里有2),
解题思路:基础题不赘述了哈,好像去年C++组的第一题也是这个呢,不过用Python写可真香
参考代码:
ans = 0
for i in range(1,2021):
ans += (str(i).count('2'))
print(ans)
运行结果是624
原问题:在一个给定的由数字 '0' 和 '2' 组成的矩阵中寻找横向往右、纵向往下和斜向往右下的 '2020' 排列,原题中给定的矩阵是300行300列的,在一个txt文件中存放。
解题思路:同样数据量不大,暴力就完事了,考试时我还不知道怎么用python读取txt,只能在控制台手动输入,最后一行输入一个1作为结束标志。
参考代码:
def check(s):
return s == '2020'
matrix = []
s = input()
while '1' not in s:
matrix.append(list(s))
s = input()
n,m = len(matrix),len(matrix[0])
ans = 0
for i in range(n):
for j in range(m):
if i + 3 < n and check(matri[i][j] + matrix[i+1][j] + matrix[i+2][j] + matrix[i+3][j]):
ans += 1
if j + 3 < m and check(matrix[i][j:j+4]):
ans += 1
if i + 3 < n and j + 3 < m and check(matri[i][j] + matrix[i+1][j+1] + matrix[i+2][j+2] + matrix[i+3][j+3]):
ans += 1
print(ans)
当时的结果好像是16520。。。记不太清了
原问题:小明坚持每天跑步,正常情况下每天跑一公里,如果这一天是周一或者月初(每月的一号),那么小明就会跑两公里(如果这一天既是周一,又是月初,小明也是跑两公里),小明从2000年1月1日(周六)一直坚持到了2020年10月1日(周四),请你计算一下小明共跑了多少公里?
解题思路:就是统计2000年1月1日到2020年10月1日(包含)以来共有多少天是周一或者月初,考试的时候绞尽脑汁写得代码,结果还错了,事后看别人题解才知道还有datetime库这个东西,我哭了。
参考代码(事后诸葛亮):
from datetime import *
start = date(2000,1,1)
end = date(2020,10,2)
tmp = timedelta(days = 1)
ans = 0
while start != end:
if start.weekday() == 0 or start.day == 1:
ans += 2
else:
ans += 1
start = start + tmp
print(ans)
运行结果为8879
问题分析:在蛇形排列矩阵中,第20行第20列的数字是多少?蛇形排列方式如图所示:
解题思路:在该数字的左上方有 19+19 = 38 个斜排,最后一个数是 38 * (38+1) / 2 = 741,741 + 20 = 761,如图所示:
如果非得编程求解的话:那就定义两种遍历模式,一种是有↗方向,一种是↙方向,判断行号加上列号的和是单数还是偶数,
参考代码:
i = 0
j = 0
num = 0
while True:
num += 1
if i == 19 and j == 19:
break
if (i+j)&1:
i += 1
if j > 0:
j -= 1
else:
j += 1
if i > 0:
i -= 1
print(num)
运行结果是761
原问题:对一个字符串,对它进行冒泡排序使其为升序,例如:对于lan,排序成 aln 需要交换一次(只能交换相邻的两个字母),对于qiao,排序成 aioq 就需要交换4次。请找出冒泡排序时恰好需要交换100次的字符串,如果有多个字符串满足条件,则找出最短的那个,如果有多个满足条件而且还是最短的,则找出字典序最小的那个。
问题分析:长度为 n 的降序数组的冒泡排序交换次数是 (n-1) * n / 2 次,大于等于100的第一个数是 105 = (15-1) * 15 / 2,所以最短的长度肯定是15了,再考虑到字典序最小,则答案应该就是onmlkjihgfedcba排列而成的,字典序最小,就需要第一个字母的字典序尽可能小,然后才是第二个、第三个……,那么就把正数第六个字母提到前面,结果应该就是jonmlkihgfedcba(当时推出来以后没有拿程序验证一下 ,心里还是很没底的)
参考验证代码:
def bubble_sort(arr):
num = 0
for i in range(len(arr)-1,0,-1):
for j in range(i):
if arr[j] > arr[j+1]:
num += 1
arr[j],arr[j+1] = arr[j+1],arr[j]
return num
print(bubble_sort(list('jonmlkihgfedcba')))
运行结果是100
第六题到第十题就是编程题了,第六题第七题很基础,第八题开始就有难度了,
问题:给定 n 个学生的成绩,大于等于60的为及格,大于等于85的为优秀。请你统计这 n 名同学的及格率和优秀率。
输入格式:第一行一个数n,表示接下来有n行数据,接下来n行每行一个数m,代表该学生的成绩。
输出格式:两行,第一行一个数表示及格率,第二行一个数表示优秀率,都要求四舍五入。
问题分析:该怎么算就不解释了哈,有点说道的地方就是后面的四舍五入和格式化输出了。
参考代码:
n = int(input())
num1 = 0
num2 = 0
for _ in range(n):
score = int(input())
if score >= 60:
num1 += 1
if score >= 85:
num2 += 1
print(str(round(num1*100/n))+'%')
print(str(round(num2*100/n))+'%')
原问题:在给定的字符串中,计算出现次数最多的字母和它的出现次数,如果出现次数最多的字母同时有多个,则找出字典序最小的。
输入格式:一行,代表所要统计的字符串
输出格式:两行,第一行一个字符,是出现最多的字母,第二行一个整数,该字母的出现次数。
解题思路:开一个哈希表统计出现次数就好了。然后从前开始遍历来保证找出的字母的字典序是最小的。
参考代码:
cnt = [0]*26
s = input()
for alpha in s:
cnt[ord(alpha) - ord('a')] += 1
k = 0
for i in range(26):
if cnt[i] > cnt[k]:
k = i
print(chr(k+ord('a')))
print(cnt[k])
原问题:在如下图所示的数字三角形中,我们需要从三角形顶部走到底部,在每一个数字处,我们可以选择向临近的右下或者临近的左下走,所经过的数字的总和称为路径和,请你计算从顶部到底部所有路线中最大的路径和为多少?同时要求这条路径选左下的次数和选右下的次数相差不能大于1。
输入格式:第一行一个整数 n ,代表数字三角形的阶数,接下来 n 行中,第 j 行有 j 个整数,代表数字三角形中的第 j 层,整数之间用空格分割。
输出格式:一个整数,代表最大的路径和。
输入样例:
6
1
2 3
7 5 6
4 3 2 3
5 6 5 7 4
7 8 9 6 10 9
输出样例:
29
解题思路:是一个比较原型的动态规划问题,一层一层向下,注意最后输出时要选最后一行的中间两个或者一个。规划过程如下图所示:
参考代码:
n = int(input())
matrix = [[0]*( _ + 1 ) for _ in range(n)]
for i in range(n):
tmp = [int(a) for a in input().split(' ')]
matrix[i] = tmp
dp = matrix[:]
for i in range(1,n):
for j in range(i+1):
if j == 0:
dp[i][j] += dp[i-1][j]
elif j == i:
dp[i][j] += dp[i-1][j-1]
else:
dp[i][j] += max(dp[i-1][j],dp[i-1][j-1])
if n&1:
print(dp[n-1][n//2])
else:
print(max(dp[n-1][n//2-1],dp[n-1][n//2]))
问题:给出N条直线的斜率和截距,计算这些直线会将xy平面划分为多少个区域。
如图中所示,这些直线将平面划分为了7个区域。
输入格式:第一行一个数 n 代表直线的个数,接下来 n 行每行两个整数,分别代表斜率和截距。
输出格式:一行一个整数,代表划分区域的个数。
输入样例:
3
1 1
2 2
3 3
输出样例:
6
解题思路:把这些直线一条一条的加入平面来进行分析,计算当前新加入的直线与之前已加入的直线集合会产生多少个交点,如果产生了k个交点,则划分的区域就会增加 k+1 个(见图所示),在计算交点的时候,需要去重,k个交点的去重时间复杂度大致为O(k*logk),共有N条直线,所以整体时间复杂度为O(N*N*logN),(题目中给出N最大为1000,只能保佑不超时了
参考代码:
n = int(input())
line = []
for _ in range(n):
tmp = [int(a) for a in input().split(' ')]
line.append(tuple(tmp))
line = list(set(line)) #去重
n = len(line)
judge = lambda pos1,pos2 : abs(pos1[0] - pos2[0]) + abs(pos1[1] - pos2[1]) < 1e-12 #判断两个点是否为同一个点
ans = 2
for i in range(1,n):
k1,b1 = line[i]
sec = []
for j in range(i):
k2,b2 = line[j]
if k2 == k1: continue
pos_x = (b2-b1)/(k1-k2); pos_y = k1*pos_x + b1 #计算交点的坐标
sec.append((pos_x,pos_y))
m = len(sec)
tmpans = m+1
#交点的数量小于等于1
if m < 2:
ans += tmpans
continue
#交点的数量大于等于2,需要去重处理
sec = sorted(sec,key=lambda x:x[0]) #对交点集合按x轴进行排列
for i in range(1,m):
if judge(sec[i-1],sec[i]):
tmpans -= 1 #有重复的,产生的区域数就减一
ans += tmpans
print(ans)
(以下题干是我根据自己的理解写的,官方的题干一堆变量名,当时看了有15分钟才明白是啥意思)
问题:在怪物猎人游戏中,玩家可以通过在装备上镶嵌宝珠来获得收益,一共有六件装备,每件装备上都有一定数量的镶嵌孔,每个镶嵌孔都有各自的等级,而宝珠也有等级,镶嵌孔只能镶嵌比自己等级低的宝珠。关于宝珠的说明,宝珠有系列划分,同系列的宝珠没有区别,每个系列的宝珠镶嵌到一定数量时,都会获得一定的收益,如下面举例:
A系宝珠等级是1级,镶嵌数量是 1,2,3,4,5 时,获得的收益分别是 1,2,3,6,7。镶嵌数量超过5个时,收益仍然为7,镶嵌数量上限为5。
B系宝珠等级是2级,镶嵌数量是 1,2,3,4 时,获得的收益分别是 2,5,8,15。镶嵌数量超过4个时,收益仍然为15。镶嵌数量上限为4,以下同理
C系宝珠等级是2级,镶嵌数量是 1,2,3,4 时,获得的收益分别是 4,7,9,13。
D系宝珠等级是3级,镶嵌数量是 1,2,3,4 时,获得的收益分别是 5,10,14,21。
可以看到,你在每个系列上的收益只与你在这个系列上花费的镶嵌孔数量有关,例如对A系宝珠而言,镶嵌3颗时,单位镶嵌孔收益为3/3 = 1,镶嵌4颗时,单位收益为6/4 = 1.5,镶嵌5颗时,单位收益为7/5 = 1.4。等级越高的宝珠系列 单位收益越高(通常而言是这样),而同等级的宝珠系列(例如B系和C系)的单位收益则显得不相上下。现在需要你找出一套镶嵌方案使总收益最大,只输出这个最大收益值即可。
输入格式:前六行代表装备上的镶嵌孔,每行第一个数代表当前装备的镶嵌孔数量,后面的数依次为镶嵌孔的等级。第七行一个整数n,代表有n个系列宝珠,接下来n行,每行代表一个系列,每行的第一个数代表当前系列宝珠的等级,第二个数代表镶嵌数量上限,接下来几个数从低到高依次代表可达到的收益。
数据限制:镶嵌孔和宝珠的等级L不超过4,每个系列的镶嵌数量上限不超过7,系列的数量不超过10000,镶嵌孔的总数不超过300。
输出格式:一个整数,代表最大收益。
输入样例:
1 1
1 1
2 1 2
2 2 1
1 2
1 3
3
1 5 1 2 3 5 8
2 4 2 5 8 15
3 4 5 10 15 21
输出样例:
20
说明:上例共有4个1级镶嵌孔,3个2级镶嵌孔,1个3级镶嵌孔。A, B, C 三个系列的宝珠,镶嵌方案为
(A)(A)(A)(A)(B)(B)(B)(B)
所以最大总收益为 5+15 = 20
解题思路:(我太菜了 想不出来,有时间再更
读题就读了半天,暴力枚举应该可以过前几个测试点,感觉有点像背包问题的意思,比赛快结束的时候码了20分钟才发现思路不对,我还是太菜了,(还不如回去检查一下,这样就能把第二题改过来了)