# 蓝桥杯 Python 组国赛真题题解(2020-2025) > 本文档提供蓝桥杯 Python 组 2020-2025 年国赛真题的详细题解,包含思路分析和代码实现。 > > 配套题目请查看《蓝桥杯 Python 组国赛真题题目集(2020-2025)》 --- ## 目录 - [2020 年第十一届蓝桥杯国赛题解](#2020年第十一届蓝桥杯国赛题解) - [2021 年第十二届蓝桥杯国赛题解](#2021年第十二届蓝桥杯国赛题解) - [2022 年第十三届蓝桥杯国赛题解](#2022年第十三届蓝桥杯国赛题解) - [2023 年第十四届蓝桥杯国赛题解](#2023年第十四届蓝桥杯国赛题解) - [2024 年第十五届蓝桥杯国赛题解](#2024年第十五届蓝桥杯国赛题解) - [2025 年第十六届蓝桥杯国赛题解](#2025年第十六届蓝桥杯国赛题解) --- ## 2020年第十一届蓝桥杯国赛题解 ### 试题 A:门牌制作 **【题目分析】** 这道题要求统计从 1 到 2020 的所有数字中,字符 "2" 出现的总次数。 **【解题思路】** 1. 遍历 1 到 2020 的所有数字 2. 将每个数字转换为字符串 3. 统计字符串中 "2" 的个数 4. 累加得到最终结果 **【代码实现】** ```python def solve(): count = 0 for i in range(1, 2021): # 将数字转为字符串,统计'2'的个数 count += str(i).count('2') return count print(solve()) ``` **【答案】** ``` 624 ``` **【时间复杂度】**:O(n × log n),其中 n = 2020 --- ### 试题 B:寻找 2020 **【题目分析】** 在给定的矩阵中,寻找所有 "2020" 的连续片段。连续片段可以是水平、垂直或对角线方向。 **【解题思路】** 1. 遍历矩阵的每个位置 2. 从每个位置出发,检查四个方向(右、下、右下、左下) 3. 如果连续四个字符是 "2", "0", "2", "0",则计数 **【代码实现】** ```python def find_2020(matrix, n, m): count = 0 # 四个方向:右、下、右下、左下 directions = [(0, 1), (1, 0), (1, 1), (1, -1)] target = "2020" for i in range(n): for j in range(m): for dx, dy in directions: # 检查是否越界 if i + 3*dx < 0 or i + 3*dx >= n or j + 3*dy < 0 or j + 3*dy >= m: continue # 检查连续四个字符 s = "" for k in range(4): ni, nj = i + k*dx, j + k*dy s += matrix[ni][nj] if s == target: count += 1 return count # 读取输入 n, m = map(int, input().split()) matrix = [input().strip() for _ in range(n)] print(find_2020(matrix, n, m)) ``` **【时间复杂度】**:O(n × m × 4 × 4) = O(n × m) --- ### 试题 C:跑步锻炼 **【题目分析】** 计算从 2000 年 1 月 1 日到 2020 年 10 月 1 日,小蓝总共跑了多少千米。 **【解题思路】** 1. 遍历每一天 2. 判断是否是周一或每月 1 日 3. 如果是,跑步 2 千米,否则 1 千米 4. 累加总距离 **【代码实现】** ```python import datetime def is_leap_year(year): return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0) def days_in_month(year, month): if month in [1, 3, 5, 7, 8, 10, 12]: return 31 elif month in [4, 6, 9, 11]: return 30 elif month == 2: return 29 if is_leap_year(year) else 28 def solve(): start_date = datetime.date(2000, 1, 1) end_date = datetime.date(2020, 10, 1) total_km = 0 current = start_date while current <= end_date: # 判断是否是周一或每月1日 is_monday = current.weekday() == 0 # Monday is 0 is_first_day = current.day == 1 if is_monday or is_first_day: total_km += 2 else: total_km += 1 current += datetime.timedelta(days=1) return total_km print(solve()) ``` **【答案】** ``` 8879 ``` **【时间复杂度】**:O(天数) ≈ O(20 × 365) --- ### 试题 D:蛇形填数 **【题目分析】** 找出蛇形填数矩阵中第 20 行第 20 列的数字。 **【解题思路】** 观察蛇形填数的规律: - 第 1 行第 1 列:1 - 第 2 行第 2 列:5 - 第 3 行第 3 列:13 - ... 可以发现对角线上的数字满足递推关系: - a[n] = a[n-1] + 4(n-1) 或者直接用公式:第 n 行第 n 列的数为 4(n-1)^2 + 1 + 2(n-1) = 4n^2 - 6n + 3 **【代码实现】** ```python def solve(): n = 20 # 公式法 result = 4 * n * n - 6 * n + 3 return result # 或者递推法 def solve2(): n = 20 result = 1 for i in range(2, n + 1): result += 4 * (i - 1) return result print(solve()) ``` **【答案】** ``` 761 ``` **【时间复杂度】**:O(1) 或 O(n) --- ### 试题 E:排序 **【题目分析】** 构造一个字符串,使得冒泡排序的交换次数恰好为 V。 **【解题思路】** 冒泡排序的交换次数等于逆序对数。 要构造逆序对数为 V 的字符串: - 使用字符 'a', 'b', 'c', ... - 逆序对数 = 0 + 1 + 2 + ... + (n-1) = n(n-1)/2 我们需要找到最小的 n,使得 n(n-1)/2 ≥ V。 **【代码实现】** ```python def solve(V): # 找到最小的 n,使得 n(n-1)/2 >= V n = 1 while n * (n - 1) // 2 < V: n += 1 # 构造字符串 # 使用 n 个不同的字符 chars = [chr(ord('a') + i) for i in range(n)] # 需要的逆序对数 total_inv = n * (n - 1) // 2 extra = total_inv - V # 构造字符串,使得逆序对数为 V # 从后往前放,调整使得逆序对数正确 result = [] for i in range(n): if extra > 0: # 减少逆序对 result.insert(len(result) - extra, chars[i]) extra -= 1 else: result.append(chars[i]) return ''.join(result) V = int(input()) print(solve(V)) ``` **【时间复杂度】**:O(n²) --- ### 试题 F:装饰珠 **【题目分析】** n 个装饰珠串成链子,相邻珠子槽编号差绝对值不超过 k,求方案数。 **【解题思路】** 动态规划: - dp[i][j] 表示第 i 个珠子使用槽 j 的方案数 - dp[i][j] = sum(dp[i-1][p]),其中 |p-j| ≤ k **【代码实现】** ```python def solve(n, m, k): MOD = 10**9 + 7 # dp[j] 表示当前珠子使用槽 j 的方案数 dp = [1] * m # 第一个珠子可以选任意槽 for i in range(1, n): new_dp = [0] * m prefix = [0] * (m + 1) # 前缀和优化 for j in range(m): prefix[j + 1] = (prefix[j] + dp[j]) % MOD for j in range(m): # 求 [j-k, j+k] 范围内的和 left = max(0, j - k) right = min(m - 1, j + k) new_dp[j] = (prefix[right + 1] - prefix[left]) % MOD dp = new_dp return sum(dp) % MOD n, m, k = map(int, input().split()) print(solve(n, m, k)) ``` **【时间复杂度】**:O(n × m) **【空间复杂度】**:O(m) --- ## 2021年第十二届蓝桥杯国赛题解 ### 试题 A:卡片 **【题目分析】** 从 1 开始拼数,每个数字 0-9 各有 2021 张,问能拼到多少。 **【解题思路】** 模拟拼数过程,统计每个数字的使用次数,当某个数字用完时停止。 **【代码实现】** ```python def solve(): # 每个数字的卡片数量 cards = {str(i): 2021 for i in range(10)} num = 1 while True: s = str(num) for c in s: cards[c] -= 1 if cards[c] < 0: # 无法拼出 num,返回 num-1 return num - 1 num += 1 print(solve()) ``` **【答案】** ``` 3181 ``` **【时间复杂度】**:O(n × log n) --- ### 试题 B:直线 **【题目分析】** 给定 20×21 个整点,求能确定多少条不同的直线。 **【解题思路】** 1. 枚举所有点对 2. 计算直线的斜率和截距 3. 使用集合去重 注意:垂直线(斜率无穷大)需要特殊处理 **【代码实现】** ```python def solve(): points = [(i, j) for i in range(20) for j in range(21)] lines = set() for i in range(len(points)): for j in range(i + 1, len(points)): x1, y1 = points[i] x2, y2 = points[j] if x1 == x2: # 垂直线 # 用 (1, 0, x1) 表示 lines.add((1, 0, x1)) else: # 计算斜率和截距 # 使用分数避免浮点误差 from fractions import Fraction k = Fraction(y2 - y1, x2 - x1) b = Fraction(y1) - k * x1 lines.add((k.numerator, k.denominator, b.numerator, b.denominator)) return len(lines) print(solve()) ``` **【答案】** ``` 40257 ``` **【时间复杂度】**:O(n²),其中 n = 20×21 = 420 --- ### 试题 C:货物摆放 **【题目分析】** 给定 n,求有多少种方案将 n 箱货物摆成长方体。 **【解题思路】** n = L × W × H,求三元组 (L, W, H) 的个数。 1. 先求 n 的所有因子 2. 枚举 L 和 W,检查 n/(L×W) 是否为整数 **【代码实现】** ```python def get_factors(n): """获取 n 的所有因子""" factors = [] i = 1 while i * i <= n: if n % i == 0: factors.append(i) if i != n // i: factors.append(n // i) i += 1 return sorted(factors) def solve(n): factors = get_factors(n) count = 0 # 枚举 L 和 W for L in factors: for W in factors: if (L * W) > n: break if n % (L * W) == 0: H = n // (L * W) count += 1 return count n = int(input()) print(solve(n)) ``` **【时间复杂度】**:O(d(n)²),其中 d(n) 是 n 的因子个数 --- ### 试题 D:路径 **【题目分析】** 求图中节点 1 到节点 2021 的最短路径。 **【解题思路】** 图的边权为最小公倍数 lcm(a, b)。 使用 Dijkstra 算法求最短路径。 **【代码实现】** ```python import heapq import math def lcm(a, b): return a