备战蓝桥杯国赛【Day 10】

一、例题精讲

例题 1:三带一

项目 内容
类型 字符串 + 模拟
核心 统计字符出现次数,判断是否为AAAB型
题目描述

小蓝和小桥玩斗地主,小蓝只剩四张牌了,判断是否是"三带一"牌型。

三带一 :四张手牌中,有三张一样,另外一张不与其他牌相同 ,即 AAAB 型。

输入 : T T T 轮,每轮一个长度为4的字符串

输出 :每轮输出 YesNo

关键思路

判断逻辑

  1. 去重后只有 2种字符len(set(s)) == 2
  2. 其中一种出现 1次或3次s.count(s[0]) == 1 or s.count(s[0]) == 3

💡 为什么这样判断? 因为四张牌只有两种字符,如果第一种出现1次,第二种必出现3次;如果第一种出现3次,第二种必出现1次。两种情况都是三带一!

推演验证
复制代码
输入: 222K

set('222K') = {'2', 'K'} → len=2 ✓
'222K'.count('2') = 3 → 满足条件 ✓

输出: Yes ✓

输入: 2233
set('2233') = {'2', '3'} → len=2 ✓
'2233'.count('2') = 2 → 不满足条件 ✗

输出: No ✓
题解
python 复制代码
t = int(input())
for _ in range(t):
    s = input()
    # 去重后只有2种字符,且其中一种出现1次或3次
    if len(set(s)) == 2 and (s.count(s[0]) == 1 or s.count(s[0]) == 3):
        print('Yes')
    else:
        print('No')

复杂度 :时间 O ( T × 4 ) O(T \times 4) O(T×4),空间 O ( 1 ) O(1) O(1)

关键细节
坑点 说明
s.count(s[0]) 统计第一个字符出现次数,利用对称性判断
len(set(s))==2 必须恰好2种字符,1种(AAAA)或3种都不行
或运算的优先级 and 优先级高于 or,需要加括号!

例题 2:DNA序列修正 ⭐重点

项目 内容
类型 贪心 + 模拟
核心 优先交换修正两个位置,无法交换则替换
题目描述

两条DNA序列,需要让第二条与第一条互补(A-T, C-G)。

操作规则

  1. 选择第二条DNA的任意两个位置,交换他们的字符(一次修正两个位置)
  2. 选择第二条DNA任意一个位置,替换为A/C/G/T中的一个(一次修正一个位置)

限制 :每个位置上的碱基只能被操作一次

目标 :求最小操作次数

关键思路

贪心策略:能交换就不替换!

  • 交换操作:一次可以修正两个位置,代价为1
  • 替换操作:一次只能修正一个位置,代价为1

所以优先尝试交换,无法交换的位置再用替换。

交换条件 :对于位置 i i i 和 j j j:

  • b [ i ] b[i] b[i] 应该是 a [ i ] a[i] a[i] 的互补碱基
  • b [ j ] b[j] b[j] 应该是 a [ j ] a[j] a[j] 的互补碱基
  • 交换后: b [ i ] b[i] b[i] 变成 d i c [ a [ i ] ] dic[a[i]] dic[a[i]] 且 b [ j ] b[j] b[j] 变成 d i c [ a [ j ] ] dic[a[j]] dic[a[j]]

即:b[j] == dic[a[i]]b[i] == dic[a[j]]

推演验证
复制代码
输入: 
N=5
a = ACGTG
b = ACGTC

dic = {'A':'T','T':'A','C':'G','G':'C'}

位置0: a[0]=A, dic[A]=T, b[0]=A ≠ T ❌
位置1: a[1]=C, dic[C]=G, b[1]=C ≠ G ❌
位置2: a[2]=G, dic[G]=C, b[2]=G ≠ C ❌
位置3: a[3]=T, dic[T]=A, b[3]=T ≠ A ❌
位置4: a[4]=G, dic[G]=C, b[4]=C == C ✓

遍历位置0:
  找j>0满足 b[j]==dic[a[0]]=T 且 b[0]==dic[a[j]]
  j=3: b[3]=T == dic[A]=T ✓, b[0]=A == dic[T]=A ✓
  交换b[0]和b[3]: b变成 TCGCA
  ans=1

遍历位置1:
  b[1]=C ≠ dic[C]=G ❌
  找j>1满足条件... 找不到
  ans=2 (替换)

等等,这样得到2,但样例输出是2... ✓

实际上位置1和位置2也可以交换:
  b[1]=C, b[2]=G
  交换后: b[1]=G(✓), b[2]=C(✓)
  ans=2 ✓
题解
python 复制代码
N = int(input())
a = list(input())
b = list(input())
dic_of_DNA = {'A':'T', 'T':'A', 'C':'G', 'G':'C'}
ans = 0

for i in range(N):
    if b[i] != dic_of_DNA[a[i]]:  # 位置i不匹配
        # 贪心:优先找可以交换的位置j
        for j in range(i + 1, N):
            # 交换条件:b[j]是a[i]的互补,且b[i]是a[j]的互补
            if b[j] == dic_of_DNA[a[i]] and b[i] == dic_of_DNA[a[j]]:
                b[i], b[j] = b[j], b[i]  # 交换
                break  # 找到就退出
        ans += 1  # 一次操作(交换或替换)

print(ans)

复杂度 :时间 O ( N 2 ) O(N^2) O(N2),空间 O ( 1 ) O(1) O(1)

关键细节
坑点 说明
交换条件 b[j]==dic[a[i]] and b[i]==dic[a[j]],必须双向满足
break的重要性 找到交换对象后立即break,避免重复操作
ans统计 无论交换还是替换,ans都+1,因为都是一次操作
贪心正确性 交换一次修两个,替换一次修一个,优先交换一定最优

例题 3:计算函数值 ⭐数学转化

项目 内容
类型 递归 + 数学
核心 发现规律:S(x) = 二进制中1的个数 + 1 + 1 +1
题目描述

神秘函数 S ( x ) S(x) S(x) 定义:

  • S ( 0 ) = 1 S(0) = 1 S(0)=1
  • x x x 为偶数: S ( x ) = S ( x / 2 ) S(x) = S(x/2) S(x)=S(x/2)
  • x x x 为奇数: S ( x ) = S ( x − 1 ) + 1 S(x) = S(x-1) + 1 S(x)=S(x−1)+1

求 S ( x ) S(x) S(x) 的值。

关键思路

手动推演找规律

复制代码
S(0) = 1
S(1) = S(0) + 1 = 2
S(2) = S(1) = 2
S(3) = S(2) + 1 = 3
S(4) = S(2) = 2
S(5) = S(4) + 1 = 3
S(6) = S(3) = 3
S(7) = S(6) + 1 = 4

发现规律

x 二进制 S(x) 二进制1的个数
0 0 1 0 + 1
1 1 2 1 + 1
2 10 2 1 + 1
3 11 3 2 + 1
4 100 2 1 + 1
5 101 3 2 + 1
6 110 3 2 + 1
7 111 4 3 + 1

结论S(x) = 二进制表示中1的个数 + 1 + 1 +1

推演验证(样例)
复制代码
输入: x=7

7 = 111,1的个数 = 3
S(7) = 3 + 1 = 4 ✓

递归验证:
S(7) = S(6) + 1
     = S(3) + 1
     = S(2) + 1 + 1
     = S(1) + 2
     = S(0) + 1 + 2
     = 1 + 3 = 4 ✓
题解

解法一:直接递归(题目给定范围 x ≤ 10 6 x \leq 10^6 x≤106,递归深度最多20层)

python 复制代码
x = int(input())

def sm(x):
    if x == 0:
        return 1
    if x % 2 == 0:
        return sm(x // 2)
    else:
        return sm(x - 1) + 1

print(sm(x))

解法二:利用二进制性质( O ( log ⁡ x ) O(\log x) O(logx))

python 复制代码
x = int(input())
# S(x) = 二进制1的个数 + 1
print(bin(x).count('1') + 1)

复杂度

  • 递归版:时间 O ( log ⁡ x ) O(\log x) O(logx)(递归深度),空间 O ( log ⁡ x ) O(\log x) O(logx)(递归栈)
  • 二进制版:时间 O ( log ⁡ x ) O(\log x) O(logx),空间 O ( 1 ) O(1) O(1)
关键细节
坑点 说明
递归终止条件 x==0 返回1,不是0
奇偶判断 先判断偶数(x%2==0),因为0也是偶数
数学规律 发现 S ( x ) = p o p c o u n t ( x ) + 1 S(x) = popcount(x) + 1 S(x)=popcount(x)+1 可以极大简化代码

例题 4:穿越时空之门 ⭐进制转换

项目 内容
类型 进制转换 + 枚举
核心 二进制数位之和 == 四进制数位之和
题目描述

计算1到2024中,有多少个数满足:二进制表示中各数位之和 == 四进制表示中各数位之和

关键思路

进制转换方法

  • 二进制bin(n) 返回 '0b1010',去掉前缀后求各位数字和
  • 四进制:不断除以4取余,直到商为0

四进制转换过程

复制代码
以 6 为例:
6 ÷ 4 = 1 ... 2
1 ÷ 4 = 0 ... 1
所以 6 的四进制 = 12,数位和 = 1 + 2 = 3

6 的二进制 = 110,数位和 = 1 + 1 + 0 = 2
不相等!
推演验证
复制代码
i=1:  二进制=1(和=1), 四进制=1(和=1) → 相等 ✓
i=2:  二进制=10(和=1), 四进制=2(和=2) → 不相等
i=3:  二进制=11(和=2), 四进制=3(和=3) → 不相等
i=4:  二进制=100(和=1), 四进制=10(和=1) → 相等 ✓
i=5:  二进制=101(和=2), 四进制=11(和=2) → 相等 ✓
题解
python 复制代码
def base4(s):
    """求四进制表示的数位之和"""
    l = []
    while s >= 4:
        s, b = divmod(s, 4)  # s=商, b=余数
        l.append(b)
    l.append(s)  # 最后的商
    return sum(l)

def base2(s):
    """求二进制表示的数位之和"""
    # bin(5) = '0b101', split('b')[1] = '101'
    return sum(list(map(int, bin(s).split('b')[1])))

ans = 0
for i in range(1, 2025):
    if base2(i) == base4(i):
        ans += 1

print(ans)

复杂度 :时间 O ( 2024 × log ⁡ 2024 ) O(2024 \times \log 2024) O(2024×log2024),空间 O ( 1 ) O(1) O(1)

关键细节
坑点 说明
divmod(s, 4) 同时返回商和余数,避免两次运算
bin(s).split('b')[1] 去掉'0b'前缀,获取纯二进制字符串
范围 range(1, 2025) 包含1到2024
四进制最后一步 循环结束后s<4,直接加入列表

例题 5:依依的画作

项目 内容
类型 字符串 + 模拟
核心 前一个的个位 != 后一个的十位
题目描述

N N N 个两位正整数,统计有多少对相邻数字不遵循规则(前一个的个位应该等于后一个的十位)。

关键思路

字符串索引

  • 个位:a[i][1](字符串的第二个字符)
  • 十位:a[i+1][0](字符串的第一个字符)

统计 :遍历 0 0 0 到 N − 2 N-2 N−2,统计 a[i][1] != a[i+1][0] 的次数。

推演验证
复制代码
输入: 5
      66 13 22 55 98

i=0: 66[1]=6, 13[0]=1 → 6≠1 ❌ 不遵循
i=1: 13[1]=3, 22[0]=2 → 3≠2 ❌ 不遵循
i=2: 22[1]=2, 55[0]=5 → 2≠5 ❌ 不遵循
i=3: 55[1]=5, 98[0]=9 → 5≠9 ❌ 不遵循

总共4对不遵循

输出: 4 ✓
题解
python 复制代码
n = int(input())
a = list(map(str, input().split()))

# 统计不遵循规则的相邻对数
print(sum(1 for i in range(n - 1) if a[i][1] != a[i + 1][0]))

复杂度 :时间 O ( N ) O(N) O(N),空间 O ( 1 ) O(1) O(1)

关键细节
坑点 说明
字符串索引 a[i][1]是个位,a[i+1][0]是十位
map(str, ...) 输入直接当字符串处理,避免转int再转str
遍历范围 range(n-1),最后一对是a[n-2]a[n-1]
简洁写法 sum(1 for ... if ...) 是Pythonic的计数方式

二、今日刷题总结

题号 题目 考点 难度 核心技巧
1 三带一 字符串统计 ⭐⭐ set()去重 + count()计数
2 DNA序列修正 贪心模拟 ⭐⭐⭐ 优先交换,双向匹配条件
3 计算函数值 递归数学 ⭐⭐⭐ 发现规律: p o p c o u n t ( x ) + 1 popcount(x) + 1 popcount(x)+1
4 穿越时空之门 进制转换 ⭐⭐⭐ divmod() + bin()
5 依依的画作 字符串索引 ⭐⭐ 字符串索引 + 生成器表达式

模拟题解题模板

python 复制代码
# 模板1:字符统计类
cnt = {}
for c in s:
    cnt[c] = cnt.get(c, 0) + 1
# 或直接用 collections.Counter

# 模板2:贪心交换类
for i in range(n):
    if not match(i):
        for j in range(i + 1, n):
            if can_swap(i, j):
                swap(i, j)
                break
        ans += 1

# 模板3:进制转换类
def to_base(n, base):
    """将n转换为base进制,返回数位列表"""
    digits = []
    while n >= base:
        n, r = divmod(n, base)
        digits.append(r)
    digits.append(n)
    return digits[::-1]  # 反转得到正序

# 模板4:字符串索引类
# 两位数的个位和十位
units = s[1]      # 个位
tens = s[0]       # 十位

三、结语

模拟题是蓝桥杯的送分题 ,但也是丢分重灾区。今天的5道题告诉我们:

🌟 今日收获

  1. 字符串处理要熟练:set()count()、索引访问
  2. 贪心思想:能交换就不替换,能一次解决就不分两次
  3. 数学观察:递归函数先手动算几项,找规律
  4. 进制转换:divmod()bin() 是利器
  5. Pythonic写法:sum(1 for ... if ...) 简洁高效

模拟题没有固定的算法模板,但有固定的解题套路:读题→找规律→写代码→验证。多练多总结,国赛模拟题全AC不是梦!💪


如果本文对你有帮助,欢迎 点赞 👍 + 收藏 ⭐ + 关注 🔔,你的支持是我持续更新的动力!

相关推荐
handler011 天前
速通蓝桥杯省一: 前缀和&差分(附经典例题)
c语言·c++·笔记·职场和发展·蓝桥杯
WL_Aurora1 天前
备战蓝桥杯国赛【Day 9】
python·算法·蓝桥杯
WL_Aurora2 天前
备战蓝桥杯国赛【Day 8】
算法·蓝桥杯
良木生香2 天前
【C++初阶】STL——List从入门到应用完全指南(1)
开发语言·数据结构·c++·程序人生·算法·蓝桥杯·学习方法
故事和你912 天前
蓝桥杯-2026年C++B组省赛
开发语言·数据结构·c++·算法·蓝桥杯·动态规划·图论
handler013 天前
速通蓝桥杯省一:二分算法
c语言·开发语言·c++·笔记·算法·职场和发展·蓝桥杯
WL_Aurora4 天前
备战蓝桥杯国赛【Day 6】
python·算法·蓝桥杯
Epiphany.5564 天前
连通块的遍历
c++·算法·蓝桥杯
H_BB5 天前
第17届蓝桥杯备战历程
c++·算法·职场和发展·蓝桥杯