作者的话:
该篇文章会不定期更新题目和题解,直至完成蓝桥杯官网对应的2020年所有题
题目链接
难度: 简单 标签: 字符串, 暴力, 2020, 省赛
小蓝正在学习一门神奇的语言,这门语言中的单词都是由小写英文字母组 成,有些单词很长,远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词,他准备不再完全记忆这些单词,而是根据单词中哪个字母出现得最多来分辨单词。
现在,请你帮助小蓝,给了一个单词后,帮助他找到出现最多的字母和这 个字母出现的次数。
输入一行包含一个单词,单词只由小写英文字母组成。
对于所有的评测用例,输入的单词长度不超过 1000。
输出两行,第一行包含一个英文字母,表示单词中出现得最多的字母是哪 个。如果有多个字母出现的次数相等,输出字典序最小的那个。
第二行包含一个整数,表示出现得最多的那个字母在单词中出现的次数。
输入
lanqiao
输出
a
2
输入
longlonglongistoolong
输出
o
6
最大运行时间:1s
最大运行内存: 256M
import os
import sys
words = list(input())
# print(words) ['l', 'a', 'n', 'q', 'i', 'a', 'o']
# 可以将string拆分成由单个字母组成的列表
words = sorted(words) # 将字母按字典序顺序排好
max_num = 0
# 寻找最大的出现次数
for i in set(words):
pre = words.count(i)
max_num = max(max_num, pre)
# 按字典序顺序寻找第一个最大的字母,即保证多个字母出现次数并列最多时输出的字典序最小
for j in words:
if words.count(j) == max_num:
print(j)
print(max_num)
break
题目链接
难度: 简单 标签: 数学, 暴力, 2020, 省赛
小蓝给学生们组织了一场考试,卷面总分为 100 分,每个学生的得分都是一个 0 到 100 的整数。
如果得分至少是 60 分,则称为及格。如果得分至少为 85 分,则称为优秀。
请计算及格率和优秀率,用百分数表示,百分号前的部分四舍五入保留整 数。
输入的第一行包含一个整数 n (1≤n≤104),表示考试人数。
接下来 n 行,每行包含一个 0 至 100 的整数,表示一个学生的得分。
输出两行,每行一个百分数,分别表示及格率和优秀率。百分号前的部分 四舍五入保留整数。
输入
7
80
92
56
74
88
100
0
输出
71%
43%
最大运行时间:1s
最大运行内存: 256M
import os
import sys
scores = [0] * 3 # 不及格 及格 优秀 (统计人数)
n = int(input())
for i in range(n):
score = int(input())
if score >= 85:
scores[2] += 1
elif score >= 60 and score < 85:
scores[1] += 1
else :
scores[0] += 1
print("{:.0f}%".format((scores[1]+scores[2])/n * 100)) # 及格率
print("{:.0f}%".format((scores[2])/n * 100)) # 优秀率
题目链接
难度: 中等 标签: 模拟, 构造, 2020, 省赛
2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。
有人表示 20200202 是 “千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。
也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 “千年一遇”,顶多算 “千年两遇”。
给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。
输入包含一个八位整数 N,表示日期。
对于所有评测用例,110000101≤N≤89991231,保证 NN 是一个合法日期的 8 位数表示。
输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。
输入
20200202
输出
20211202
21211212
最大运行时间:1s
最大运行内存: 256M
import os
import sys
# 判断日期是否合法的函数
def date_legal(a):
runnian = 0 # 是否为闰年
legal = 0 # 日期是否合法
# 记录 30天和 31天的月份 2月份根据是否为闰年特判
month1 = {1, 3, 5, 7, 8, 10, 12}
month2 = {4, 6, 9, 11}
if (int(a) % 4 == 0 and int(a) % 100 != 0) or int(a) % 400 == 0: # 判断是否为闰年
runnian = 1
if int(a[:-3:-1]) in month1:
if int(a[-3::-1]) <= 31 and int(a[-3::-1]) >= 1: # 判断日期是否合法
legal = 1
elif int(a[:-3:-1]) in month2:
if int(a[-3::-1]) <= 30 and int(a[-3::-1]) >= 1:
legal = 1
elif int(a[:-3:-1]) == 2: # 如果为2月
if runnian: # 闰年29天
if int(a[-3::-1]) <= 29 and int(a[-3::-1]) >= 1:
legal = 1
else:
if int(a[-3::-1]) <= 28 and int(a[-3::-1]) >= 1:
legal = 1
else: # 不合法月份
return 0
return legal
n = input()
a = int(n[:4])
isHuiWen = 1
while True:
state = int(str(a)+str(a)[::-1]) > int(n) # 判断当前遍历的日期是否大于起始N
if date_legal(str(a)) and isHuiWen and state:
print(str(a)+str(a)[::-1])
isHuiWen = 0
# 判断是否为ABABBABA
if str(a)[:2] == str(a)[2:4] and date_legal(str(a)) and str(a)[0] != str(a)[1] and state:
print(str(a)+str(a)[::-1])
break
a += 1
题目链接
难度: 简单 标签: 填空题, 2020, 省赛
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝要为一条街的住户制作门牌号。
这条街一共有 2020 位住户,门牌号从 1 到 2020 编号。
小蓝制作门牌的方法是先制作 0 到 9 这几个数字字符,最后根据需要将字符粘贴到门牌上,例如门牌 1017 需要依次粘贴字符 1、0、1、7,即需要 1个字符 0,2 个字符 1,1 个字符 7。
请问要制作所有的 1 到 2020号门牌,总共需要多少个字符 2?
最大运行时间:1s
最大运行内存: 128M
import os
import sys
# 数位统计DP 的简化版本
"""
实现 count(n, x), 1~n中x出现的次数
分别求出x在每一位上出现的次数 分情况讨论:
例如: n = abcdefg, 求x在第4位出现的次数
1. 前三位: 000 ~ abc-1, x, 后三位: 000 ~ 999 方案数: abc*1000
2. 前三位: abc, x
2.1 d < x, 后三位: 无解 方案数: 0
2.2 d = x, 后三位: 000 ~ efg 方案数: efg + 1
2.3 d > x, 后三位: 000 ~ 999 方案数: 1000
注意:
特判1:0不能出现在最高位
特判2:当x在最高位出现时,不存在情况1
特判3:当 x = 0 时,情况1前三位需要从001开始
"""
def get(num, l, r):
res = 0
for i in range(l, r+1):
res = res * 10 + num[i]
return res
def count(n, x):
if not n: return 0
num = [int(x) for x in str(n)] # 将n拆分成多位数字的列表
res, n = 0, len(num)
for i in range(n):
if x == 0 and i == 0: continue # 特判1
# 情况1
if i > 0: # 特判2
res += get(num, 0, i-1) * 10 ** (n-i-1)
if not x:
res -= 10 ** (n-i-1) # 特判3
# 情况2.2
if num[i] == x:
res += get(num, i+1, n-1) + 1
# 情况2.3
elif num[i] > x:
res += 10 ** (n-i-1)
return res
# 本题 即 count(2020, 2)
print(count(2020, 2))
题目链接
难度: 简单 标签: 动态规划, 2020, 省赛
上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过 1。
输入的第一行包含一个整数 N (1≤N≤100),表示三角形的行数。
下面的 N 行给出数字三角形。数字三角形上的数都是 0 至 100 之间的整数。
输出一个整数,表示答案。
输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出
27
最大运行时间:1s
最大运行内存: 256M
import os
import sys
# 线性DP 经典模板题 数字三角形 的进阶版
"""
状态表示:f[i, j] 所有从起点(1, 1)走到(i, j)的路径 存储 Max
状态计算:
f[i, j] = max( f[i-1, j-1] + a[i, j], f[i-1][j] + a[i, j] )
由于向左下走的次数与向右下走的次数相差不能超过 1
所以 答案只能在最后一层中间位置产生
奇数行 最中间一个
偶数行 中间两个
"""
n = int(input())
a = [[0] * (n+1) for _ in range(n+1)]
f = [[0] * (n+1) for _ in range(n+1)]
for i in range(1, n+1):
a[i][1:n+1] = [int(x) for x in input().split()]
f[1][1] = a[1][1] # 起点
for i in range(2, n+1):
for j in range(1, i+1): # 1 ~ i 不然会越界
f[i][j] = max( f[i-1][j-1] + a[i][j], f[i-1][j] + a[i][j] )
if n % 2 == 1: # 奇数行 取最中间
print(f[n][n//2 + 1])
else: # 偶数行 取中间两个中最大的
print(max( f[n][n//2], f[n][n//2 + 1] ))
题目链接
难度: 简单 标签: 模拟, 暴力, 2020, 省赛
小蓝给学生们组织了一场考试,卷面总分为 100 分,每个学生的得分都是一个 0 到 100 的整数。
请计算这次考试的最高分、最低分和平均分。
输入的第一行包含一个整数 n (1≤n≤104),表示考试人数。
接下来 n 行,每行包含一个 0 至 100 的整数,表示一个学生的得分。
输出三行。
第一行包含一个整数,表示最高分。
第二行包含一个整数,表示最低分。
第三行包含一个实数,四舍五入保留正好两位小数,表示平均分。
输入
7
80
92
56
74
88
99
10
输出
99
10
71.29
最大运行时间:1s
最大运行内存: 256M
import os
import sys
n = int(input())
scores = []
for i in range(n):
scores.append(int(input()))
print(max(scores))
print(min(scores))
print("{:.2f}".format(sum(scores)/n))
题目链接
难度: 简单 标签: 填空题, 2020, 省赛
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。
在冒泡排序中,每次只能交换相邻的两个元素。
小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符, 则在所有可能的排序方案中,冒泡排序的总交换次数是最少的。
例如,对于字符串 lan 排序,只需要 1 次交换。对于字符串 qiao 排序,总共需要 4 次交换。
小蓝找到了很多字符串试图排序,他恰巧碰到一个字符串,需要 100 次交 换,可是他忘了吧这个字符串记下来,现在找不到了。
请帮助小蓝找一个只包含小写英文字母且没有字母重复出现的字符串,对 该串的字符排序,正好需要 100 次交换。如果可能找到多个,请告诉小蓝最短的那个。如果最短的仍然有多个,请告诉小蓝字典序最小的那个。
最大运行时间:1s
最大运行内存: 128M
import os
import sys
"""
最差序列冒泡排序交换次数:(n-1) + (n-2) + …… + 2 + 1 == [n*(n-1)/2]
(当然如果不知道的话,可以枚举总结规律)
故考虑该情况下,易得 7 * 7 = 49 ==> n = 15
即 abcdefghijklmno 这些字母组成的 字符串字典序最小
15 * 14 / 2 = 105
对于完全逆序情况,需要少交换5次,且为了保证字典序最小
那么得到答案 j onmlk ihgfedcba
"""
print("jonmlkihgfedcba")
题目链接
难度: 简单 标签: 填空题, 2020, 省赛
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
如下图所示,小明用从 1 开始的正整数“蛇形”填充无限大的矩阵。
1 2 6 7 15 ...
3 5 8 14 ...
4 9 13 ...
10 12 ...
11 ...
...
容易看出矩阵第二行第二列中的数是 5。请你计算矩阵中第 20 行第 20 列的数是多少?
最大运行时间:1s
最大运行内存: 128M
import os
import sys
"""
可以直接画图找规律
得到 n行 n列 = n-1行 n-1列 + 4 * (n-1)
"""
res = 1
for i in range(1, 21):
res += 4 * (i-1)
print(res)
题目链接
难度: 简单 标签: 填空题, 2020, 省赛
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝每天都锻炼身体。
正常情况下,小蓝每天跑 1 千米。如果某天是周一或者月初(1 日),为了激励自己,小蓝要跑 2 千米。如果同时是周一或月初,小蓝也是跑 2 千米。
小蓝跑步已经坚持了很长时间,从 2000 年 1 月 1 日周六(含)到 2020 年 10 月 1 日周四(含)。请问这段时间小蓝总共跑步多少千米?
最大运行时间:1s
最大运行内存: 128M
由于是和日期有关的题目,我们可以使用Python的标准库 datetime 库
下面给出一个知乎链接:datetime 库详解
我们需要用到的函数和方法有:
datetime.date(year,month,day),创建一个实例,返回格式为year-month-day。
weekday(),返回该日期对应星期几,用[0,6]代表星期一到星期日。
下面方案一中为对datetime类型数据进行遍历,实现了一个迭代器,并附上参考文章链接:yield 详解
import os
import sys
from datetime import date, timedelta
t1 = date(2000, 1, 1)
t2 = date(2020, 10, 1)
ans = 0
# ——————方案一—————— 通过自定义迭代器遍历日期
def date_range(start_date, end_date):
for n in range(0, int((end_date - start_date).days) + 1):
yield start_date + timedelta(n)
for t in date_range(t1, t2):
if t.weekday() == 0 or t.day == 1: # 如果这一天是星期一 或 月初
ans += 2
else:
ans += 1
print(ans)
# ——————方案二—————— 通过 timedelta 实现日期的递增
days = timedelta(days = 1)
while t1 <= t2:
if t1.day == 1 or t1.weekday() == 0:
ans += 2
else:
ans += 1
t1 += days
print(ans)
题目链接
难度: 简单 标签: 填空题, 2020, 省赛
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝要用七段码数码管来表示一种特殊的文字。
上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二 极管,分别标记为a,b,c,d,e,f,g。
小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符 的表达时,要求所有发光的二极管是连成一片的。
例如:b 发光,其他二极管不发光可以用来表达一种字符。
例如:c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上 一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a,b,c,d,e 发光,f,g 不发光可以用来表达一种字符。
例如:b,f 发光,其他二极管不发光则不能用来表达一种字符,因为发光 的二极管没有连成一片。
请问,小蓝可以用七段码数码管表达多少种不同的字符?
最大运行时间:1s
最大运行内存: 128M
import os
import sys
"""
1. 用 1 ~ 7 来代表 a ~ g;
2. 若某两个二极管相邻,那么就在它们之间连一条边(无向图);
3. 先用 dfs 枚举出二极管的所有亮灭情况;
4. 再用 并查集 判断是否只有一个连通块;
"""
# 用邻接矩阵来描述图,即二极管之间是否相邻
def add(a, b):
g[a][b] = g[b][a] = 1
# 并查集中find根节点操作,并进行路径压缩
def find(x):
if p[x] != x:
p[x] = find(p[x])
return p[x]
# 深度优先搜索,暴力搜出所有点亮情况
def dfs(u):
global ans
if u == 8: # 7个二极管全部点亮了
for i in range(1, 8):
p[i] = i # 重置并查集的7个根节点
for i in range(1, 8):
for j in range(1, 8):
if g[i][j] == 1 and st[i] and st[j]:
p[find(i)] = find(j) # 合并两个集合
cnt = 0
# 判断是否只有一个连通块 通过判断
for i in range(1, 8):
if st[i] and p[i] == i:
cnt += 1
# 不为一的时候表明点亮的灯是不连通的
if cnt == 1:
ans += 1
return
st[u] = True # 打开第u个二极管
dfs(u+1) # 下一个情况
st[u] = False # 恢复现场
dfs(u+1)
if __name__ == "__main__":
N = 10
ans = 0
g = [[0]*N for _ in range(N)] # 图的存储
p, st = [0]*N, [False]*N # p存储该节点的父节点,根节点为本身 st为DFS的状态
add(1, 2), add(1, 6)
add(2, 3), add(2, 7)
add(3, 4), add(3, 7)
add(4, 5)
add(5, 6), add(5, 7)
add(6, 7)
dfs(1)
print(ans) # 80
题目链接
难度: 简单 标签: 填空题, 2020, 省赛
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
如果一个分数的分子和分母的最大公约数是 1,这个分数称为既约分数。
例如 3/4, 1/8, 7/1, 都是既约分数。
请问,有多少个既约分数,分子和分母都是 1 到 2020 之间的整数(包括 1 和 2020)?
最大运行时间:2s
最大运行内存: 128M
本题和最大公约数有关,在求最大公约数时,一般使用辗转相除法,需要用到下面这个定理
可以手动递归实现,也可以使用math库中的gcd()函数实现。
gcd(a, b) = gcd(b, a mod b)
import os
import sys
import math
ans = 0
# 利用math库求解最大公约数
for i in range(1, 2021):
for j in range(1, 2021):
if math.gcd(i, j) == 1:
ans += 1
print(ans)
# 手写求最大公约数的辗转相除法 运行超时
def gcd(a, b):
if b == 0:
return a
else:
return gcd(b, a % b)
for i in range(1, 2021):
for j in range(1, 2021):
if gcd(i, j) == 1:
ans += 1
print(ans)