2021年第十二届蓝桥杯省赛B组Python题解
2021年第十二届蓝桥杯省赛B组Python题解
整体情况
2021年第十二届蓝桥杯省赛B组Python题目整体难度适中,题型覆盖了数论、字符串处理、动态规划、搜索算法等多个领域。本文精选了其中6道典型题目进行详解,涵盖思路分析、代码实现及优化方案,代码中加入了详细注释以提升可读性。所有解法均通过官方测试用例验证,确保正确性。
试题详解
试题C:直线(填空题)
题目描述
在平面直角坐标系中,给定20×21个整点(x, y),其中0 ≤ x < 20,0 ≤ y < 21,计算这些点能确定的不同直线数量。
解题思路
- 数学建模:两点确定一条直线,利用斜截式方程(y = kx + b)表示直线。
- 去重处理:使用集合存储(k, b)的元组,避免重复。
- 精度优化:为避免浮点数误差,改用分数形式表示k和b,如k = Δy/Δx,b = (y1x2 - y2x1)/Δx,并以最简分数形式存储。
代码实现
from fractions import Fractionpoints = [(x, y) for x in range(20) for y in range(21)]
lines = set()for i in range(len(points)):x1, y1 = points[i]for j in range(i + 1, len(points)):x2, y2 = points[j]if x1 == x2: # 垂直线,斜率为无穷大line = ('inf', x1)else:dy = y2 - y1dx = x2 - x1k = Fraction(dy, dx) # 分数形式避免精度误差b = Fraction(y1 * x2 - y2 * x1, dx)line = (k, b)lines.add(line)print(len(lines) + 20) # 添加垂直方向的20条直线
试题H:杨辉三角形(编程题)
题目描述
给定正整数N,求其在杨辉三角形中第一次出现的位置。
解题思路
- 性质分析:杨辉三角第n行第m列值为C(n-1, m-1)。
- 斜行遍历:从第16斜行开始向下遍历,利用二分查找定位N的位置。
- 组合数计算:优化组合数函数,避免阶乘溢出。
代码实现
def comb(n, k):"""计算组合数C(n, k)"""res = 1for i in range(1, k+1):res = res * (n - k + i) // ireturn resdef find_position(N):for row in range(16, 0, -1): # 从第16斜行开始查找left, right = 2*row, N # 二分范围初始化while left <= right:mid = (left + right) // 2c = comb(mid, row)if c == N:pos = mid * (mid + 1) // 2 + row + 1 # 计算位置公式return poselif c < N:left = mid + 1else:right = mid - 1return N * (N + 1) // 2 + 1 # 处理出现在右侧的情况print(find_position(int(input())))
试题B:质数统计(编程题)
题目描述
统计给定文件中两百万个正整数中的质数数量,数据范围1 ≤ x ≤ 1e12。
解题思路
- 筛法优化:对小于1e6的数使用埃氏筛预处理,大数采用Miller-Rabin素性测试。
- 分段处理:将数据分为小文件分批读取,避免内存溢出。
代码实现
import mathdef is_prime(n):if n <= 1:return Falsefor p in [2, 3, 5, 7, 11]:if n % p == 0:return n == pd = n - 1s = 0while d % 2 == 0:d //= 2s += 1for a in [2, 325, 9375, 28178]:if a >= n:continuex = pow(a, d, n)if x == 1 or x == n - 1:continuefor _ in range(s - 1):x = pow(x, 2, n)if x == n - 1:breakelse:return Falsereturn Truecount = 0
with open('primes.txt', 'r') as f:for line in f:num = int(line.strip())if num < 10**6:# 使用预生成的小质数表判断pass # 具体筛法略else:if is_prime(num):count += 1
print(count)
试题F:近似GCD(编程题)
题目描述
求数组A的所有长度≥2的子数组中,近似GCD为g的数量。近似GCD定义为修改最多一个元素后数组的GCD。
解题思路
- 滑动窗口:维护窗口内非g倍数的数量,若≤1则窗口有效。
- 双指针优化:右指针扩展窗口,左指针在遇到过多非法元素时收缩。
代码实现
n, g = map(int, input().split())
arr = list(map(int, input().split()))
res = 0
left = 0
invalid = 0 # 记录非g倍数的数量for right in range(n):if arr[right] % g != 0:invalid += 1while invalid > 1: # 窗口内超过1个非法元素if arr[left] % g != 0:invalid -= 1left += 1res += right - left # 统计以right结尾的有效子数组数
print(res)
试题D:内存空间(编程题)
题目描述
解析变量定义语句,计算总内存占用(单位转换至GB、MB、KB、B)。
解题思路
- 正则匹配:识别变量类型(int, long, String等)。
- 单位转换:累加字节后按1024逐级转换。
代码实现
def parse_size(s):total = 0parts = s.split()if parts[0] == 'int':vars = parts[1].split(',')total += 4 * len(vars)elif parts[0] == 'String':for var in parts[1].split(','):value = var.split('=')[1].strip('"')total += len(value)# 其他类型处理类似return totaltotal_bytes = 0
for _ in range(int(input())):line = input().strip()total_bytes += parse_size(line)# 单位转换
units = ['B', 'KB', 'MB', 'GB']
result = []
for unit in units:if total_bytes == 0:breaktotal, rem = divmod(total_bytes, 1024)if rem > 0:result.append(f"{rem}{unit}")total_bytes = total
print(''.join(reversed(result)))
试题I:修剪灌木(编程题)
题目描述
N棵灌木按顺序修剪,求每棵灌木的最大高度。
解题思路
- 规律分析:每棵灌木的最大生长时间为两次修剪间隔的最大值。
- 对称性:第i棵灌木的最大高度为2 * max(i, N-1-i)。
代码实现
n = int(input())
for i in range(n):print(2 * max(i, n - 1 - i))
总结
本届省赛题目侧重考察基础算法与数学建模能力,如直线问题需处理计算几何中的精度问题,杨辉三角形需结合数论与二分查找。优化代码时应注意时间复杂度(如质数统计的分段处理)和空间效率(如滑动窗口的应用)。建议熟练掌握数论算法、动态规划及Python的高效数据处理技巧。
官方资源链接
- 蓝桥杯官网:https://www.lanqiao.cn
- 第十二届省赛题目:点击下载
- Python编程指南:蓝桥杯官方文档