2022(第十三届蓝桥杯)模拟赛 Python组

2022(第十三届蓝桥杯)模拟赛 Python组

2022.03.30
比赛参加的太迟了,还不知道排名。但是比赛的视频讲解可以看了。
欢迎在评论区里讨论,共同进步。


2022.03.27
这两周太堕落了,沉迷王者,从早上打到晚上,惭愧惭愧。差点忘记了今天
模拟赛结束的最后一天。垃圾王者,毁我青春。
12点03分做完了,检查了一遍。填空题最后两题不会写编程,最后两道大题没有做。
考试时一定要注意问答题的数据范围,合理的进行骗分。
认真读题,仔细检查。

填空题

第1题

最简单的方法是把矩阵复制到word中,“查找”字母A有多少个。
问题描述
以下是一个 25 行 25 列的字母矩阵,全部由字母 A 和 B 组成。
  AAAAAAABABBAABABABAAAAAAA
  ABBBBBABBAABBBBBABABBBBBA
  ABAAABABBBABAABBBBABAAABA
  ABAAABABBBBBAABAABABAAABA
  ABAAABABBABABBABABABAAABA
  ABBBBBABBBABAABBBBABBBBBA
  AAAAAAABABABABABABAAAAAAA
  BBBBBBBBABAABABBBBBBBBBBB
  AABAABABBAAABBAAABABBBBBA
  ABBABABBBABBAAAABBBBAAAAB
  BBBBAAABABAABABAABBBAABBA
  BBAABABABAAAABBBAABBAAAAA
  ABABBBABAABAABABABABBBBBA
  AAAABBBBBABBBBAAABBBABBAB
  AABAABAAABAAABAABABABAAAA
  ABBBBBBBBABABBBBABAABBABA
  ABBBAAABAAABBBAAAAAAABAAB
  BBBBBBBBABBAAABAABBBABBAB
  AAAAAAABBAAABBBBABABAABBA
  ABBBBBABBAABABAAABBBABBAA
  ABAAABABABBBAAAAAAAAAABAA
  ABAAABABABABBBABBAABBABAA
  ABAAABABBABBABABAABAABAAA
  ABBBBBABABBBBBABBAAAABAAA
  AAAAAAABAABBBAABABABBABBA
  请问在这个矩阵中有多少个字母A?
答案提交
  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

mat1 = 'AAAAAAABABBAABABABAAAAAAAABBBBBABBAABBBBBABABBBBBAABAAABABBBABAABBBBABAAABAABAAABABBBBBAABAABABAAABAABAAABABBABABBABABABAAABAABBBBBABBBABAABBBBABBBBBAAAAAAAABABABABABABAAAAAAABBBBBBBBABAABABBBBBBBBBBBAABAABABBAAABBAAABABBBBBAABBABABBBABBAAAABBBBAAAABBBBBAAABABAABABAABBBAABBABBAABABABAAAABBBAABBAAAAAABABBBABAABAABABABABBBBBAAAAABBBBBABBBBAAABBBABBABAABAABAAABAAABAABABABAAAAABBBBBBBBABABBBBABAABBABAABBBAAABAAABBBAAAAAAABAABBBBBBBBBABBAAABAABBBABBABAAAAAAABBAAABBBBABABAABBAABBBBBABBAABABAAABBBABBAAABAAABABABBBAAAAAAAAAABAAABAAABABABABBBABBAABBABAAABAAABABBABBABABAABAABAAAABBBBBABABBBBBABBAAAABAAAAAAAAAABAABBBAABABABBABBA'

cnt = mat1.count('A')
print(cnt)

# =============================================================================
# cnt = mat1.count('B')
# print(cnt) # 317
# =============================================================================

318

第2题

问题描述
  如果一个整数的某个数位包含 2 ,则称这个数为一个“最2数字”。例如:102、2021 都是最2数字。
  请问在 1(含) 到 2021(含) 中,有多少个最2数字。
答案提交
  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

cnt = 0
for i in range(1, 2021 + 1):
    if '2' in str(i):
        cnt += 1
print(cnt)

564

第3题

问题描述
  有一个整数 A=2021,每一次,可以将这个数加 1 、减 1 或除以 2,其中除以 2 必须在数是偶数的时候才允许。
  例如,2021 经过一次操作可以变成 2020、2022。
  再如,2022 经过一次操作可以变成 2021、2023 或 1011。
  请问,2021 最少经过多少次操作可以变成 1。
答案提交
  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
解题思路
每个整数看成一个点,如果两个点经过一次操作变过去的话就连一条有向边。看成最短路径的问题。BFS

from collections import deque
q = deque()
dis = [1] * 2100 # 存距离
vis = [0] * 2100 # 每个点是否访问过

q.append(2021) # 起点放到队列里

vis[2021] = 1 # 2021已经访问过了
dis[2021] = 0 # 2021的距离设置为0
while q:
    x = q.popleft() # 只要队列不空就出队
    if x == 1: # 到1就停止
        break
    if vis[x + 1] == 0: # 如果x + 1没有访问过
        q.append(x + 1) # 就把他放进队列中
        vis[x + 1] = 1
        dis[x + 1] = dis[x] + 1 # x + 1 的距离就是x的距离加上1
    if vis[x - 1] == 0: # 如果x - 1没有访问过
        q.append(x - 1) # 就把他放进队列中
        vis[x - 1] = 1
        dis[x - 1] = dis[x] + 1 # x - 1 的距离就是x的距离加上1
    if x % 2 == 0 and vis[x // 2] == 0:
        q.append(x // 2)  # 就把他放进队列中
        vis[x // 2] = 1
        dis[x // 2] = dis[x] + 1  # x // 2 的距离就是x的距离加上1
print(dis[1]) # 把到1的距离输出
print(14)
# 当时做题的时候没有想到用广度搜索算法
2021 - 1 = 2020
2020 / 2 = 1010
1010 / 2 = 505
505 - 1 = 504
504 / 2 = 252
252 / 2 = 126
126 / 2 = 63
63 + 1 = 64
64 / 2 = 32 
32 / 2 = 16
16 / 2 = 8
8 / 2 = 4 
4 / 2 = 2
2 / 2 = 1

补充
Python 队列(先进先出),这篇博客把python的队列讲明白了。
Python 队列 collections.deque——快速和稳健的队列
deque类实现了一个双端队列,支持在时间(非均摊)中从任一端添加和删除元素。由于deque支持从两端添加和移除元素,因此既可用作队列也可用作栈。

Python的deque对象以双向链表实现。这为插入和删除元素提供了出色且一致的性能,但是随机访问位于栈中间元素的性能很差,耗时为。

因此,默认情况下collections.deque是Python标准库中不错的队列型数据结构:

from collections import deque
>>> q = deque()
>>> q.append('eat')
>>> q.append('sleep')
>>> q.append('code')

>>> q
deque(['eat', 'sleep', 'code'])

>>> q.popleft()
'eat'
>>> q.popleft()
'sleep'
>>> q.popleft()
'code'

>>> q.popleft()
IndexError: "pop from an empty deque"

第4题

问题描述
  对于一个 n 行 m 列的表格,我们可以使用螺旋的方式给表格依次填上正整数,我们称填好的表格为一个螺旋矩阵。
  例如,一个 4 行 5 列的螺旋矩阵如下:
  1 2 3 4 5
  14 15 16 17 6
  13 20 19 18 7
  12 11 10 9 8
  请问,一个 30 行 30 列的螺旋矩阵,第 20 行第 20 列的值是多少?
答案提交
  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

模拟的方法来做。

# 第一种解法
# 这是一道填空题,而且矩阵是正方形,所以处理比较简单
m, n = 30, 30
r, c = 20, 20
a = [[0] * m for i in range(n)]
def inb(x, y):
    return ((x >= 0) and (x < m) and (y >= 0) and (y < m))
dx = [0,1,0,-1] # 保存要转换的方向
dy = [1,0,-1,0]
x, y, d  = 0, 0, 0
a[x][y] = 1
for i in range(2, m * n):
    nx = x + dx[d]
    ny = y + dy[d]
    if inb(nx, ny) and a[nx][ny] == 0:
        x = nx
        y = ny
        a[nx][ny] = i
    else:
        d = (d + 1) % 4 # 换方向
        nx = x + dx[d]
        ny = y + dy[d]
        x = nx
        y = ny
        a[nx][ny] = i
print(a[r-1][c-1])
# 第二种解法
# 矩阵不是正方形也可以进行正确的旋转
def make_mat(x, y):
    global cnt 
    while cnt <= n * m:
        while y < m and mat[x][y] == 0:
            mat[x][y] = cnt
            y += 1
            cnt += 1
        y -= 1
        x += 1
        while x < n and mat[x][y] == 0:
            mat[x][y] = cnt
            x += 1
            cnt += 1
        x -= 1
        y -= 1
        
        while y >= 0 and mat[x][y] == 0:
            mat[x][y] = cnt
            y -= 1
            cnt += 1
        y += 1
        x -= 1
        while x >= 0 and mat[x][y] == 0:
            mat[x][y] = cnt
            x -= 1
            cnt += 1
        x += 1
        y += 1
n, m = list(map(int, input().split())) # n 行 m 列的矩阵
r, c = 20, 20  # 第 20 行第 20 列的值是多少
cnt = 1
mat = [[0] * m for i in range(n)]
make_mat(0, 0)
print(mat[r - 1][c - 1])
819

第5题

问题描述
  一棵二叉树有2021个结点。该树满足任意结点的左子树结点个数和右子树的结点个数之差最多为1。
  定义根结点的深度为0,子结点的深度比父结点深度多1。
  请问,树中深度最大的结点的深度最大可能是多少?
答案提交
  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

平衡树有多少层。
f(2021) = f(1010) + 1
f(1010) = f(505) + 1
f(n) = f(n / 2) + 1
在python中,//表示整除,/表示除。

n = 2021
def f(n):
    if n == 1: # 只有一个节点的深度为0
        return 0
    else:
        return f(n // 2) + 1
print(f(n))
10

编程题

第1题

问题描述
  一个和尚要挑水,每次最多能挑 a 千克,水缸最多能装 t 千克,开始时水缸为空。
  请问这个和尚最少要挑多少次可以将水缸装满?
输入格式
  输入一行包含两个整数 a, t,用一个空格分隔。
输出格式
  输出一行包含一个整数,表示答案。
样例输入
20 2021
样例输出
102
评测用例规模与约定
  对于所有评测用例,1 <= a <= 100,1 <= t <= 10000。


# 这么简单的题都能做错,什么都没有考虑到。第1道大题送分都没有拿到。
a, t = map(int, input().split()) # 错误代码
print(t // a + 1) # 整除不了再进行加1 的情况都没有考虑到

# 正确答案
a, t = map(int, input().split())
ans = t // a
if t % a != 0: # 如果不能整除再进行加1
    ans += 1
print(ans)

第2题

问题描述
在金融领域,通常将金额的百位和千位之间、十万位和百万位之间增加逗号(千分位分隔符),以方便阅读。一般从个位开始,每三位之前增加一个逗号。
  例如:1234567890.00 通常写成 1,234,567,890.00。
  注意小数点后固定保留 2 位。
  给定一个包含千分位分隔符的数值,请读入后输出对应的不含千分位的数值,小数点仍然保留 2 位。
输入格式
  输入一行包含一个由千分位分隔符的数值,恰好有 2 位小数。
输出格式
  输出不含千分位分隔符的数值,保留 2 位小数。
样例输入
1,234,567,890.00
样例输出
1234567890.00
评测用例规模与约定
  对于所有评测用例,给定的数值整数部分不超过12位。


a = input()
res = []
for i in a:
    if i != ',' and i != '.':
       res.append(i)
# print(res[-1])
# print(res[-2])
cnt = 0
len1 = len(res) - 3

for i in res[:-2:]:
    cnt += (int(i) * (10 ** len1))
    # print(i, cnt)
    len1 -= 1

cnt += (int(res[-2]) * 0.1 + int(res[-1]) * 0.01)
print('{:.2f}'.format(cnt)) # 这个代码有测试出来错误示例的欢迎再评论区交流

一道比较简单的字符串处理的题。

# 做题的时候把题目想的太难了
s = input()
for i in s:
    if i != ',':
        print(i, end = '') # 

第3题

问题描述
  小蓝有一个插板,形状用一个 n * m 的01矩阵表示,0 表示板面,1 表示插孔。
  小蓝还有一个插头,形状用一个 r * c 的01矩阵表示,0 表示没有伸出的部分,1 表示伸出的部分。插头伸出的部分必须插在插孔里面。
  为了安全,插头插到面板上不能有任何部分超过插板边界(包括没有伸出的部分)。
  插头和插板都不能旋转,也不能翻转。请求出插头插入插板的合理位置。
输入格式
  输入的第一行包含两个整数 n, m。
  接下来 n 行,每行一个长度为 m 的01串,表示插板的形状。
  接下来一行包含两个整数 r, c。
  接下来 r 行,每行一个长度为 c 的01串,表示插头的形状。
输出格式
  如果插头没办法安全插入插板中,输出“NO”。否则输出两个数 a, b,表示插头的第 1 行第 1 列对应插板的第 a 行第 b 列。如果有多种情况满足要求,输出 a 最小的方案,如果 a 最小的方案有多个,输出在 a 最小的前提下 b 最小的方案。
样例输入
3 4
0110
0000
0000
3 3
000
010
000
样例输出
NO
样例说明
  在插头不超出范围的前提下无法插入。
样例输入
4 7
1110100
1101111
0001111
0000011
2 3
111
011
样例输出
2 4
评测用例规模与约定
  对于 50% 的评测用例,2 <= n, m, r, c <= 20。
  对于所有评测用例,2 <= n, m, r, c <= 100。
  
n,m,r,c的数据范围再在100以内,直接枚举就可以了。

怎么写都有一个空白行输出,但是不能在练习系统里面进行测试,所以不知道对最后的得分有没有影响

# ① 函数写法
n, m = map(int, input().split())
chaban = []
for i in range(n):
    cnt = list(map(int, input().strip()))
    chaban.append(cnt)
r, c = map(int, input().split())
chatou = []
for i in range(r):
    cnt = list(map(int, input().strip()))
    chatou.append(cnt)

def ok(a,b):
    for i in range(r):
        for j in range(c):
            # s chaban / t  chatou
            # chatou[i][j]<->chaban[a+i][b+j]
            if chatou[i][j] == 1 and chaban[a+i][b+j] != 1:
                return False
    return True

def f(n, m, r, c):
    cnt = 0
    for a in range(n - r + 1):
        for b in range(m - c + 1): # 确定a, b 的位置
            if ok(a, b):
                cnt += 1
                print(a + 1, b + 1) # 下标加 1 进行输出
                # 题目要求输出最小的方案 只要找个一种方法就退出
                return # 会多输出一行空白行
    if cnt == 0:
        print('NO') # 答案为NO也会输出一行空白行 
f(n, m, r, c)

# 不会做,直接输出NO骗分
n, m = map(int, input().split())
chaban = []
for i in range(n):
    cnt = list(map(int, input().split())) # 按照题目
    chaban.append(cnt)
r, c = map(int, input().split())
chatou = []
for i in range(r):
    cnt = list(map(int, input().split()))
    chatou.append(cnt)
print('NO')

第4题

问题描述
  给定正整数 a, b, c,请问有多少个正整数,是其中至少两个数的约数。
输入格式
  输入一行包含三个正整数 a, b, c。
输出格式
  输出一行包含一个整数,表示答案。
样例输入
30 70 35
样例输出
6
样例说明
  1、2、5、7、10、35满足条件。
评测用例规模与约定
  对于 50% 的评测用例,1 <= a, b, c <= 1000000。
  对于所有评测用例,a, b, c 不超过 10^12(10的12次方)。

# 求出a, b   a,c   b,c的最大公约数g
# 两个数的约数一定是最大公约数的约数
# 约数总是成对出现的,只用枚举道根号g的范围内
import math
a, b, c = map(int, input().split())
ans = set()
# ==============================================================
# def gcd(a, b): # 辗转相除法求最大公约数
#     if b == 0:
#         return a
#     return gcd(b, a % b)
# ==============================================================

def solve(a,b):
    g = math.gcd(a, b)
    for i in range(1, int(g ** 0.5) + 1):
        if g % i == 0: # 把a, b的约束加入到集合中
            ans.add(i)
            ans.add(g // i)

solve(a, b)
solve(a, c)
solve(b, c)
print(len(ans))

a, b, c = map(int, input().split())
max1 = max(a, b, c)
min1 = min(a, b, c)
max2 = a + b + c - max1 - min1
cnt = 0
for i in range(1, max2 + 1):
    if (a % i == 0 and b % i == 0) or (a % i == 0 and c % i == 0)  or (c % i == 0 and b % i == 0):
        cnt += 1
        # print(i)
print(cnt)

第5题

问题描述
  小蓝很喜欢玩汉诺塔游戏。
  游戏中有三根柱子,开始时第一根柱子上有 n 个圆盘,从上到下圆盘的大小依次为 1 到 n。
  每次,可以将一个盘子从一根柱子上移动到另一根柱子上,这个盘子必须是柱子最上方的盘子,而且移到的柱子上的盘子必须比这个盘子大。
  小蓝的目标是将所有的盘子移动到第三根柱子上。
  汉诺塔是个经典问题,当盘子数量为 n 时,最少需要移动 2 ** n - 1 步,其中 2**n 表示 2 的 n 次方。
  小蓝已经玩了一会儿(不一定按最优方案玩),他想知道,对于他目前的局面,最少还需要多少步可以到达目标。
输入格式
  输入的第一行包含三个非负整数 a, b, c,分别表示目前每根柱子上的盘子数。在本题中,n=a+b+c。
  第二行包含 a 个整数,相邻的整数之间使用一个空格分隔,表示第一根柱子上的盘子,盘子按从上到下(从小到大)的顺序给出。
  第三行包含 b 个整数,相邻的整数之间使用一个空格分隔,表示第二根柱子上的盘子,盘子按从上到下(从小到大)的顺序给出。
  第四行包含 c 个整数,相邻的整数之间使用一个空格分隔,表示第三根柱子上的盘子,盘子按从上到下(从小到大)的顺序给出。
输出格式
  输出一行包含一个整数,表示答案。
样例输入
1 2 3
1
2 3
4 5 6
样例输出
7
评测用例规模与约定
  对于 30% 的评测用例,2 <= n <= 5。
  对于所有评测用例,2 <= n <= 60。

# 

def f(n, k): # 递归
    if n == 0: # 边界条件 0个盘子就不用移动了
        return 0
    if p[n] == k:
        return f(n - 1, k)
    return f(n - 1, 6 - k - p[n]) + (1 << (n-1))

a, b, c = map(int, input().split())
n = a + b + c
d = [[0] * 4 for i in range(100)] # 从1 开始来存储
p = [0] * 100 # p用来存个盘子初始在哪根柱子上
list1 = list(map(int, input().split()))
list2 = list(map(int, input().split()))
list3 = list(map(int, input().split()))
for i in range(a):
    d[1][i] = list1[i]
    p[d[1][i]] = 1
for i in range(b):
    d[2][i] = list2[i]
    p[d[2][i]] = 2
for i in range(c):
    d[3][i] = list3[i]
    p[d[3][i]] = 3
print(f(n, 3))

你可能感兴趣的:(蓝桥杯省赛,leetcode,python,算法)