【第十四届 蓝桥杯省赛B组】试题解析

一、2023.

1. 考点:枚举

2. 难度:⭐⭐⭐

3. 要点分析

利用列表的pop(),来检验顺序的正确性,是一个很好的思路。

count = 0
for i in range(12345678, 98765432+1):
    x = [t for t in str(i)]
    if '2' not in x and '0' not in x and '3' not in x:
        continue
    pos = ['2', '0', '2', '3']
    for t in x:
        if len(pos)>0 and pos[0]==t:
            pos.pop(0)

    if len(pos)==0:
        count += 1
      
print(98765433-12345678-count)

二、硬币兑换。

1. 考点:枚举

2. 难度:⭐⭐

3. 要点分析:

①读懂题目(一开始我就没看懂...)。

②枚举的时候,注意是否有重复计算。

import sys

# 兑换出来的硬币最大为 4046 
result = [0]*(2023*2+1)

for i in range(2, 2023+1):
    for j in range(1, 2023+1):
        if i==j:  #币值相同
            result[i+j] += i//2
        else:   #币值不同
            result[i+j] += min(i,j)

print(max(result)//2)   #2+3和3+2属于同种情况,循环里重复计算了

三、松散子序列。

1. 考点:动态规划

2. 难度:⭐⭐⭐⭐

3. 要点分析

(1)状态表示。

 eq?dp%5Bi%5D 表示到序列第i个位置时的最优值。

(2)转移关系(选择当前元素、不选择当前元素)。

eq?dp%5Bi%5D%20%3D%20max%28dp%5Bi-1%5D%2C%20dp%5Bi-2%5D+s%5Bi%5D%29

前半部分表示当前不选该位置元素,后半部分表示当前选择该位置元素。

(3)初始状态:

eq?dp%5B0%5D%3Ds%5B0%5D%3Bdp%5B1%5D%3Dmax%28s%5B0%5D%2Cs%5B1%5D%29

由于相邻之间的元素不能取,因此需要获得前两个位置的最佳选择。

基于转移关系,可推导:eq?i-2%5Cgeqslant%200%2Ci%5Cgeqslant%202

(4)边界条件。

如果序列中只有一个元素,则子序列的值为该元素的值。

def dps(s):
    # 记录数组
    dp = [0] * len(s)

    # 初始条件1
    dp[0] = ord(s[0]) - 96

    # 边界条件
    if len(s) == 1:
        return dp[-1]
    
    # 初始条件2
    dp[1] = max(ord(s[0]) - 96, ord(s[1]) - 96)

    # 状态转移
    for i in range(2, len(s)):
        dp[i] = max(dp[i - 1], dp[i - 2] + (ord(s[i])) - 96)
    return dp[-1]

s = input()
print(dps(s))

四、管道。

1. 考点:二分、贪心

2. 难度:⭐⭐⭐

3. 要点分析:

①每一次开闸时的水流覆盖区域,可以看作是一条“线段”,这样便将问题转化为“区间覆盖”问题。

“二分法”的应用场景在于,存在一个“临界值”可以将整体分成两个部分,一部分满足条件,另一部分不满足;利用“二分法”找到满足条件的时间,大大地减少了计算量。

③如果二分得到的时间点 mid 符合条件,因为大于 mid 的时间点也一定符合条件,所以更新 right=mid,否则更新 left=mid+1;重复这个过程,直到搜索范围的左右端点相等,此时就找到了最早的时间。 

import sys

n, length = map(int, input().split())
l = [0]*n
s = [0]*n
for i in range(n):
    l[i], s[i] = map(int, input().split())

def check(t):
    cover = []
    for i in range(n):
        cover.append([max(1,l[i]-t+s[i]), min(l[i]+t-s[i],length)])
    
    cover = sorted(cover)
    if cover[0][0]!=1:
        return False
    
    point = cover[0][1] #表示已经覆盖到的区域
    for i in range(1, n):
        if cover[i][0]-point > 1: #左端点与右端点的差值不超过1
            break
        else:
            point = max(point, cover[i][1]) #更新覆盖区域
    return point>=length

left, right = 1, 10**10
t = 0
while left < right:
    mid = (left+right)//2
    if check(mid):
        # print(mid)
        right = mid
    else:
        left = mid+1
print(right)

五、保险箱。

1. 考点:动态规划

2. 难度:⭐⭐⭐⭐⭐

3. 要点分析

(1)状态表示。

eq?dp%5Bi%5D%5Bj%5D 表示第i个位置的第j种方法。

(2)转移关系(退位、不进不退、退位)。

eq?dps%5Bi%5D%5B0%5D%3Dmin%28dps%5Bi-1%5D&plus;abs%28s1%5Bi%5D-s2%5Bi%5D%29%2Cdps%5Bi-1%5D&plus;abs%28%281&plus;s1%5Bi%5D%29&plus;s2%5Bi%5D%29%2Cdps%5Bi-1%5D&plus;abs%28%28s1%5Bi%5D-1%29&plus;s2%5Bi%5D%29%29        

eq?dps%5Bi%5D%5B1%5D%3Dmin%28dps%5Bi-1%5D&plus;10-s1%5Bi%5D&plus;s2%5Bi%5D%29%2Cdps%5Bi-1%5D&plus;10-%281&plus;s1%5Bi%5D%29&plus;s2%5Bi%5D%2Cdps%5Bi-1%5D&plus;10-%28s1%5Bi%5D-1%29&plus;s2%5Bi%5D%29

eq?dps%5Bi%5D%5B0%5D%3Dmin%28dps%5Bi-1%5D&plus;10&plus;s1%5Bi%5D-s2%5Bi%5D%2Cdps%5Bi-1%5D&plus;10&plus;%281&plus;s1%5Bi%5D%29-s2%5Bi%5D%2Cdps%5Bi-1%5D&plus;10&plus;%28s1%5Bi%5D-1%29-s2%5Bi%5D%29

(3)初始状态。

eq?dp%5B0%5D%5B0%5D%3Dabs%28s1%5B0%5D-s2%5B0%5D%29        ——不进不退

eq?dp%5B0%5D%5B1%5D%3D10-s1%5B0%5D&plus;s2%5B0%5D        ——往前转&进位

eq?dp%5B0%5D%5B2%5D%3D10&plus;s1%5B0%5D-s2%5B0%5D        ——往后转&退位

如:3 --> 1

不进不退:3,2,1(2个)

进位:3,4,5,6,7,8,9,0,1(8个)

退位:3,2,1,0,9,8,7,6,5,4,3,2,1(12个)

import sys
n = int(input())
s1 = input()[::-1]
s2 = input()[::-1]

#字符串反转后第一位是个位,第二位是十位...
s1 = [int(t) for t in s1]
s2 = [int(t) for t in s2]

dp = [[0]*3 for _ in range(n+1)]
dp[0][0] = abs(s1[0]-s2[0]) #不进退直接加减
dp[0][1] = 10-s1[0]+s2[0]   #进位
dp[0][2] = 10+s1[0]-s2[0]   #退位

for i in range(1,n):
    """
        上一位不进退直接加减后这一位也直接加减;
        上一位进位后这一位多个1,然后直接加减;
        上一位退位后这一位少个1,然后直接加减。
        取最小值为直接加减次数,剩余的同理可得.
    """
    dp[i][0] = min(dp[i-1][0]+abs(s1[i]-s2[i]),dp[i-1][1]+abs(s1[i]+1-s2[i]),dp[i-1][2]+abs(s1[i]-1-s2[i]))
    dp[i][1] = min(dp[i-1][0]+10-s1[i]+s2[i],dp[i-1][1]+10-(1+s1[i])+s2[i],dp[i-1][2]+10-(s1[i]-1)+s2[i])
    dp[i][2] = min(dp[i-1][0]+10+s1[i]-s2[i],dp[i-1][1]+10+(1+s1[i])-s2[i],dp[i-1][2]+10+(s1[i]-1)-s2[i])

ans = min(dp[n-1][0],dp[n-1][1],dp[n-1][2])   #取三者最小值即为答案
print(ans)

六、树上选点。

1. 考点:

2. 难度:

3. 要点分析

 

七、T字消除。

1. 考点:

2. 难度:

3. 要点分析

 

八、独一无二。

1. 考点:

2. 难度:

3. 要点分析

 

九、异或和。

1. 考点:DFS

2. 难度:⭐⭐⭐

3. 要点分析

①用“邻接表”保存结点关系(邻接矩阵稀疏,所占空间过大),对树“深度遍历”的同时进行计算。

②注意结点之间的父子关系,编号小的结点为编号大的结点的父结点。

import sys

def dfs(pos):
    global ans
    # 终止条件:叶子结点
    if relations[pos]==[]:
        return 
    for t in relations[pos]:
        ans ^= weighted[t]
        dfs(t)

# 输入数据
n, m = map(int, input().split())
weighted = [0] + [x for x in map(int, input().split())]
relations = [[] for _ in range(n+1)]
for i in range(n-1):
    i, j = map(int, input().split())
    if i<j:
        relations[i].append(j)
    else:
        relations[j].append(i)

for i in range(m):
    info = [int(x) for x in input().split()]
    if info[0]==1:
        weighted[info[1]] = info[-1]
    elif info[0]==2:
        ans = weighted[info[1]]
        dfs(info[1])
        print(ans)

十、混乱的数组。

1. 考点:思维、构造

2. 难度:⭐⭐⭐⭐

3. 要点分析

 

 

 

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值