蓝桥杯2022年第十三届省赛真题解答Python(持续更新中)

学习笔记,有些思路代码是看题解和博客

已更新:

1、纸张尺寸(大学B、C组)

2、数位排序(大学B、C组)

3、矩形拼接(研究生组、大学A、C组)

4、GCD(大学C组)

5、峰巢(大学B、C组)

6、消除游戏(研究生组、大学A、B组)

7、质因数个数(研究生组,大学A组)

纸张尺寸(大学B、C组)

1、题目

题目描述

在 ISO 国际标准中定义了 A0 纸张的大小为 1189mm × 841mm,将 A0 纸沿长边对折后为 A1 纸,大小为 841mm × 594mm,在对折的过程中长度直接取下整(实际裁剪时可能有损耗)。将 A1 纸沿长边对折后为 A2 纸,依此类推。 输入纸张的名称,请输出纸张的大小

输入格式

输入一行包含一个字符串表示纸张的名称,该名称一定是 A0、A1、A2、A3、A4、A5、A6、A7、A8、A9 之一。

输出格式

输出两行,每行包含一个整数,依次表示长边和短边的长度。

样例输入
A0
样例输出
1189
841

2、思路

(列表、元组)

可以写一个函数,知道输入数组的数字(第二个数,比如A0的0),就可以得到对应的长和宽,本函数返回值是元组。

对应的长宽可以根据一个for循环来得到,通过观察可知l=w,w=l/2。

在函数的后面写输入、输出就好了。

3、代码

def paper_size(name):
    len=int(name[1])#name是字符串,取第二个数值
    l,w=1189,841#是0的话就直接返回
    for _ in range(len):#是0的话直接不进入循环
        l,w=w,l//2
    return l,w
name=input().strip()
l,w=paper_size(name)
print(l)
print(w)

数位排序(大学B、C组)

1、题目

题目描述

小蓝对一个数的数位之和很感兴趣,今天他要按照数位之和给数排序。当两个数各个数位之和不同时,将数位和较小的排在前面,当数位之和相等时,将数值小的排在前面。

例如,2022 排在 409 前面,因为 2022 的数位之和是 6,小于 409 的数位之和 13。

又如,6 排在 2022 前面,因为它们的数位之和相同,而 6 小于 2022。

给定正整数 n,m,请问对 1 到 n 采用这种方法排序时,排在第 m 个的元素是多少? 

输入格式

输入第一行包含一个正整数 n。

第二行包含一个正整数 m。

输出格式

输出一行包含一个整数,表示答案。

样例输入
13
5
样例输出
3

2、思路

(排序,数位之和)

第一步先写整数各个元素之和,用个函数封装起来。其思路是把整数转换为数组。

第二步是用排序函数sorted还有key,key是表示排序规则的

3、代码

#输入两个整数
n=int(input())
m=int(input())
#创建一个1到N的列表
s=[i for i in range(1,n+1)]
#函数来求整数各个元素的和
def num_sum(a):
    sum=0
    for i in str(a):
        sum+=int(i)
    return sum
#排序数组,key表示排序规则,后面跟函数
s=sorted(s,key=num_sum)
#输出别忘了
print(s[m-1])

矩形拼接(研究生组、大学A、C组)

1、题目

题目描述

已知 3 个矩形的大小依次是 a1 × b1, a2 × b2 和 a3 × b3。用这 3 个矩形能拼出的所有多边形中,边数最少可以是多少?例如用 3 × 2 的矩形(用 A 表示)、4 × 1 的矩形(用 B 表示)和 2 × 4 的矩形(用 C 表示)可以拼出如下 4 边形。

例如用 3 × 2 的矩形(用 A 表示)、3 × 1 的矩形(用 B 表示)和 1 × 1 的矩形(用 C 表示)可以拼出如下 6 边形。

输入格式

输入包含多组数据。

第一行包含一个整数 T,代表数据组数。

以下 T 行,每行包含 6 个整数 a1, b1, a2, b2, a3, b3,其中 a1, b1 是第一个矩形的边长,a2, b2 是第二个矩形的边长,a3, b3 是第三个矩形的边长。

输出格式

对于每组数据,输出一个整数代表答案。

样例输入
2
2 3 4 1 2 4
1 2 3 4 5 6
样例输出
4
6

2、思路

(for循环,枚举,数学问题)

首先得分类讨论

4条边情况:(1)3个矩形有一条相同的边(2)2个矩形的有一条边相同,且它们的另一条边也相同

6条边情况:(1)2个矩形有一条相同的边(2)2个矩形的有一条边相同,且它们的另一条边不同

8条边情况:除了上面两个的都是

(1)输入可以弄成列表形式

(2)枚举的话太多情况了,可以用暴力循环;第一个三层循环来确定矩阵,确保不重复;第二个三层循环来确定边,就可以用分类讨论里的情况,4比6多条件,可以先判断6再判断4

(3)ans很重要,默认是8,后面再修改

3、代码

#第一个输入
T = int(input())
#在循环里进行
while T:
    T -= 1
    ans = 8
    a = list(map(int, input().split()))
    a = [[a[0], a[1]], [a[2], a[3]], [a[4], a[5]]]
    #第一个三层循环是为了确定三个不同矩形
    for i in range(3):
        for j in range(3):
            for k in range(3):
                if i == j or i == k or j == k:#确保是不同矩形
                    continue
                #第二个三层循环是为了确定不同矩形的边
                for ii in range(2):
                    for jj in range(2):
                        for kk in range(2):
                            #4比6多个条件,可以先判断6,后加条件判断4
                            if a[i][ii] == a[j][jj]:
                                ans = min(ans, 6)
                                if a[i][ii] == a[k][kk]:
                                    ans = min(ans, 4)
                            #4比6多个条件,可以先判断6,后加条件判断4
                            if a[i][ii] == a[j][jj] + a[k][kk]:
                                ans = min(ans, 6)
                                if a[j][jj - 1] == a[k][kk - 1]:
                                    ans = min(ans, 4)
    print(ans)

GCD(大学C组)

1、题目

题目描述

给定两个不同的正整数 a, b,求一个正整数 k 使得 gcd(a + k, b + k) 尽可能大,其中 gcd(a, b) 表示 a 和 b 的最大公约数,如果存在多个 k,请输出所有满足条件的 k 中最小的那个。 

输入格式

输入一行包含两个正整数 a, b,用一个空格分隔。 

输出格式

输出一行包含一个正整数 k。

样例输入
5 7
样例输出
1

2、思路

(GCD变形)

求a,b的差值。考虑差值等于0和不为0情况,不为0时,返回c-a%c(我不太懂这个逻辑)

3、代码

a, b = map(int, input().split())
c = abs(b - a)
if c == 0:
    print(0)
else:
    print(c-a%c)

峰巢(大学B、C组)

1、题目

题目描述

蜂巢由大量的六边形拼接而成,定义蜂巢中的方向为:0 表示正西方向,1 表示西偏北 60◦,2 表示东偏北 60◦,3 表示正东,4 表示东偏南 60◦,5 表示西偏南 60◦。 

对于给定的一点 O,我们以 O 为原点定义坐标系,如果一个点 A 由 O 点先向 d 方向走 p 步再向 (d + 2) mod 6 方向(d 的顺时针 120◦ 方向)走 q 步到达,则这个点的坐标定义为 (d, p, q)。在蜂窝中,一个点的坐标可能有多种。

下图给出了点 B(0, 5, 3) 和点 C(2, 3, 2) 的示意。

给定点 (d1, p1, q1) 和点 (d2, p2, q2),请问他们之间最少走多少步可以到达?

输入格式

输入一行包含 6 个整数 d1, p1, q1, d2, p2, q2 表示两个点的坐标,相邻两个整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示两点之间最少走多少步可以到达。 

样例输入
0 5 3 2 3 2
样例输出
7

2、思路

(数学,坐标转换)

在一篇博客找到的原理图。可以根据此图设计六个方向,x,y轴方向如图所示。

(1)先把x,y坐标的对应列表写好

在六边形坐标系中,每个方向对应着一个 x 坐标和一个 y 坐标的增量。具体来说,六个方向分别为:

0 表示正西方向

1 表示西偏北 60°

2 表示东偏北 60°

3 表示正东方向

4 表示东偏南 60°

5 表示西偏南 60°

在这个六边形坐标系中,每个方向都有一个对应的 x 坐标和 y 坐标增量,通过这些增量我们可以计算出每个方向上的点的坐标。增量的定义如下:

当方向为 0 时,x 坐标增量为 1,y 坐标增量为 0。

当方向为 1 时,x 坐标增量为 1,y 坐标增量为 1。

当方向为 2 时,x 坐标增量为 0,y 坐标增量为 1。

当方向为 3 时,x 坐标增量为 -1,y 坐标增量为 0。

当方向为 4 时,x 坐标增量为 -1,y 坐标增量为 -1。

当方向为 5 时,x 坐标增量为 0,y 坐标增量为 -1。

(2)把输入的d1.p1,q1......转换为x,y坐标

(3)判断是否在一条直线上,在的话直接坐标相减的最大值,不在的话最小值相加

3、代码

# 读取输入
d1, p1, q1, d2, p2, q2 = map(int, input().split())
# 定义x、y方向的增量
x = [1, 1, 0, -1, -1, 0]
y = [0, 1, 1, 0, -1, -1]
# 计算点A的坐标
xa = x[d1] * p1 + x[(d1 + 2) % 6] * q1
ya = y[d1] * p1 + y[(d1 + 2) % 6] * q1
# 计算点B的坐标
xb = x[d2] * p2 + x[(d2 + 2) % 6] * q2
yb = y[d2] * p2 + y[(d2 + 2) % 6] * q2
# 计算两点之间的最小步数
if xa == xb or ya == yb or (yb - ya) * (xb - xa) > 0:
    ans = max(abs(xa - xb), abs(ya - yb))
else:
    ans = abs(xa - xb) + abs(ya - yb)
# 输出结果
print(ans)

消除游戏(研究生组、大学A、B组)

1、题目

题目描述

在一个字符串 S 中,如果 S i = S i−1 且

,则称 S i 和 S i+1 为边缘字符。如果 S i = S i−1且 S i = S i+1,则 S i−1 和 S i 也称为边缘字符。其它的字符都不是边缘字符。

对于一个给定的串 S,一次操作可以一次性删除该串中的所有边缘字符(操作后可能产生新的边缘字符)。

请问经过 264 次操作后,字符串 S 变成了怎样的字符串,如果结果为空则输出 EMPTY。 

输入格式

输入一行包含一个字符串 S 。

输出格式

输出一行包含一个字符串表示答案,如果结果为空则输出 EMPTY。

样例输入
edda
样例输出
EMPTY

2、思路

(多个列表、for循环)

(1)创建两个新列表,一是把原字符转换成列表,二是创建标志列表,用来标记边缘字符

(2)弄一个大循环

(3)每次循环开始,都要重置标志列表和字符列表长度

(4)内循环遍历两种边缘字符的情况,边缘字符标志为1

(5)创建新列表,存储边缘字符

(6)更新列表和列表长度

(7)跳出条件(更新前后长度是否相等)

(8)跳出循环后,将列表连成字符串

3、代码

st = input()  # 获取输入的字符串
st_list = list(st)  # 将字符串转换为列表,方便操作
st_flag = [0 for _ in range(len(st_list))]  # 创建标志列表,用于标记边缘字符
for c in range(2**64):  # 循环次数,确保能够在有限时间内完成操作
    st_flag = [0 for _ in range(len(st_list))]  # 在每次循环开始时,将标志列表重新置零
    l1 = len(st_list)  # 记录循环开始时的字符列表长度
    # 遍历字符串列表中的元素
    for i in range(1, len(st_list) - 1):
        # 条件一:当前字符与前一个字符相同,且与后一个字符不同
        if st_list[i] == st_list[i-1] and st_list[i] != st_list[i+1]:
            st_flag[i] = 1  # 将当前字符和后一个字符标记为边缘字符
            st_flag[i+1] = 1
        
        # 条件二:当前字符与前一个字符不同,且与后一个字符相同
        if st_list[i] != st_list[i-1] and st_list[i] == st_list[i+1]:
            st_flag[i] = 1  # 将当前字符和前一个字符标记为边缘字符
            st_flag[i-1] = 1
    # 创建一个新的列表,用于存储非边缘字符
    st_list2 = []
    for i in range(len(st_flag)):
        if st_flag[i] == 0:
            st_list2.append(st_list[i])  # 将非边缘字符添加到新列表中
    
    st_list = st_list2  # 更新字符串列表
    l2 = len(st_list)  # 删除边缘字符后的列表长度
    # 如果删除边缘字符后的长度与之前的长度相同,则说明字符串里已经没有边缘字符了,可以跳出循环
    if l2 == l1:
        break
st = ''.join(st_list)  # 将列表连接成字符串
# 输出结果,如果处理后的字符串为空,则输出'EMPTY'
if len(st) == 0: 
    print('EMPTY')
else:
    print(st)

质因数个数

1、题目

题目描述

给定正整数 n,请问有多少个质数是 n 的约数。

输入格式

输入的第一行包含一个整数 n。

输出格式

输出一个整数,表示 n 的质数约数个数。

样例输入
396
样例输出
3

2、思路

首先写个函数判断是否为质数;其次判断是否为约数

3、代码

n = int(input().strip())
k = 0
def is_number(a):  # 判断质数函数
    if a <= 1:
        return False
    for i in range(2, a):
        if a % i == 0:
            return False
    return True
for j in range(1, n):
    if is_number(j) and n % j == 0:  # 调用 is_number 函数并传递参数 j
        k += 1
print(k)