python-第14届蓝桥杯(2023.04)

前记:没做完,做了部分题,后续会补充完整的

试题A: 2023(5分)

【问题描述】

        请求出在 12345678 至 98765432 中,有多少个数中完全不包含 2023 。

        完全不包含 2023 是指无论将这个数的哪些数位移除都不能得到 2023 。

        例如 20322175,33220022 都完全不包含 2023,而 20230415,20193213 则 含有 2023 (后者取第 1, 2, 6, 8 个数位) 。

答案: 85959030

import re
pat=re.compile(r'\d*.join('2023'))
nums=range(12345678,98765432+1)
print(sum(not re.search(pat,i) for i in map(str,nums)))

在python中需要通过正则表达式对字符串进行匹配的时候,可以使用一个python自带的模块re

r:代表原始字符串标识符,该字符串中的特殊符号不会被转义

print(r"\n")#输出\n

def find_2023(s):
    one_l=s.find('2')
    if one_l==-1:
        return False
    two_l=s.find('0',one_l+1)   #从下一位开始找
    if two_l==-1:
        return False
    thrid_l = s.find('2', two_l + 1)  # 从下一位开始找
    if thrid_l == -1:
        return False
    fourth_l = s.find('3', thrid_l + 1)  # 从下一位开始找
    if fourth_l == -1:
        return False
    return True


num=0
for a in range(12345678,98765432+1,1):
    res=find_2023(str(a))
    if res is False:
        num+=1
print(num)

试题B:硬币兑换(5分)

【问题描述】

        小蓝手中有 2023 种不同面值的硬币,这些硬币全部是新版硬币,其中第i(1 ≤ ≤ 2023) 种硬币的面值为 ,数量也为 个。硬币兑换机可以进行硬币兑换,兑换规则为:交给硬币兑换机两个新版硬币 coin1 和 coin2 ,硬币兑换机会兑换成一个面值为 coin1 + coin2 的旧版硬币。

        小蓝可以用自己已有的硬币进行任意次数兑换,假设最终小蓝手中有 种不同面值的硬币(只看面值,不看新旧)并且第 i(1 ≤ ≤ K) 种硬币的个数为sumi。小蓝想要使得max{sum1, sum2, · · · , sumK} 的值达到最大,请你帮他计算这个值最大是多少。

        注意硬币兑换机只接受新版硬币进行兑换,并且兑换出的硬币全部是旧版硬币。

错误想法                                          ​​​​​​​         错误答案:513589

1+2022=2023        1

2+2021=2023        2

。。。

1011+1012=2023        1011

最后有2023个2023        2023

相加即得最大

# 513589
num=2023
for i in range(1,1012):
    num+=i
print(num)

错误之处,没有考虑两种硬币面值相加之和大于2023的情况。 

正确想法:舍弃了两种硬币的面值相同的情况,易知不是最大        正确结果:682425

res=[0]*4047

for i in range(1,2024):
    for j in range(i+1,2024):
        res[i+j]+=1

print(max(res))
        

试题C:松散子序列(10分)

考点:动态规划

【问题描述】

        给定一个仅含小写字母的字符串 ,假设 的一个子序列 的第 个字符对应了原字符串中的第 pi 个字符。我们定义 的一个松散子序列为:对于 > 1总是有 pi − pi−1 ≥ 2 。设一个子序列的价值为其包含的每个字符的价值之和 (∼ 分别为 1 ∼ 26 ) 。

        求 s 的松散子序列中的最大价值。

【输入格式】

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

【输出格式】

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

 使用动态规划解题

dp[i][0]:不取当前字符的最大价值

dp[i][1]:取当前字符的最大价值

最终取两者的较大值

状态转移方程:

dp[i][0]=max(dp[i-1][1],dp[i-1][0])

dp[i][1]=dp[i-1][0]+ord(str[i])-ord('a')+1

import os
import sys

# 请在此输入您的代码
s=input()
dp=[[0,0]for _ in range(len(s))]
#dp[i][0]表示不拿当前字符的最大价值
#dp[i][1]表示拿了当前字符的最大价值
for i in range(len(s)):
  dp[i][0]=max(dp[i-1][0],dp[i-1][1])
  dp[i][1]=dp[i-1][0]+(ord(s[i])-ord('a')+1)
print(max(dp[len(s)-1][0],dp[len(s)-1][1]))

试题D :管道(10分)

考点:贪心、二分

【问题描述】

        有一根长度为len的横向管道,该管道按照单位长度分为len段,每一段的中央有一个可打开的阀门和一个检测水流的传感器。

        一开始管道是空的,位于Li的阀门会在Si时刻打开,并不断让水流入管道。

        对于位于Li的阀门,它流入的水在Ti(Ti>=Si)时刻会使得从第Li-(Ti-Si)段到Li+(Ti-Si)段的传感器检测到水流。

        求管道种每一段中间的传感器都检测到有水流的最早时间。

【输入格式】

        输入的第一行包含两个整数n、len,用一个空格分隔,分别表示会打开的阀门数和管道长度。

        接下来n行每行包含两个整数Li,Si,用一个空格分隔,表示位于第Li段管道中央的阀门会在Si时刻打开。

【输出格式】

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

 对于题设的理解:

输入会开的阀门数(注意这里并不是每段的阀门都会打开)以及能够打开的阀门时刻Si。

我们需要找出管道中每一段的传感器都检测到有水的最早时间(注意这里是所有的传感器)。

设最早时间为T,求出来每个 会开的阀门 水流的范围,这些范围应将所有的传感器完全覆盖在内,即满足题设。

区间覆盖问题

按照区间的左端点来排序这些区间,检查这些区间是否覆盖了整个管道,如果一个区间的左端点>1,则表示管道的开始部分没有被覆盖,直接返回false;否则,设一个变量r表示可以到达的最远距离,r的初始值为第一个区间的右端点。接着检查其他区间是否和r相邻或者重叠,若当前区间和r相邻或者重叠,将当前区间的右端点和r取最大值。最后判断是否r>=len,若是,则说明成功覆盖所有的区间,否则说明没有。

n,les=map(int,input().split())
lst=[]
for i in  range(n):
    l,s=map(int,input().split())
    lst.append((l,s))
def check(time):
    res=[]
    for l,s in lst:
        temp=time-s
        if temp>=0:
            res.append([l-temp,l+temp])
    res.sort()
    ans=res[0][1]
    for i in range(1,len(res)):
        if res[i][0]-ans<=1:
            ans=max(ans,res[i][1])
        else:
            break
    return ans>=les
left=0
right=10**9
while left<right:
    mid=(left+right)//2
    if check(mid):
        right=mid
    else:
        left=mid+1
print(left)

试题E:保险箱(15分)

考点:动态规划

【问题描述】

小蓝有一个保险箱,保险箱上共有 位数字。

小蓝可以任意调整保险箱上的每个数字,每一次操作可以将其中一位增加

1 或减少 1 。

当某位原本为 9 或 0 时可能会向前(左边)进位/退位,当最高位(左边第

一位)上的数字变化时向前的进位或退位忽略。

例如:

00000 的第 5 位减 1 变为 99999 ;

99999 的第 5 位减 1 变为 99998 ;

00000 的第 4 位减 1 变为 99990 ;

97993 的第 4 位加 1 变为 98003 ;

99909 的第 3 位加 1 变为 00009 。

保险箱上一开始有一个数字 x,小蓝希望把它变成 y,这样才能打开它,问

小蓝最少需要操作的次数。

【输入格式】

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

第二行包含一个 位整数 

第三行包含一个 位整数 

【输出格式】

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

【样例输入】

5

12349

54321

【样例输出】

11

#保险箱
#输入
n=int(input())
x=list(map(int,input()))
y=list(map(int,input()))
#dp创建和初始化
dp=[[0,0,0] for _ in range(n)]
dp[n-1][0]=abs(x[n-1]-y[n-1])
#当前位置向后进位
dp[n-1][1]=abs(10+y[n-1]-x[n-1])
#当前位向前进位
dp[n-1][2]=abs(10+x[n-1]-y[n-1])
#进行遍历
for i in range(n-2,-1,-1):
    a=x[i]
    b=y[i]
    #dp[i][0]表示当前位不向前进位或退位
    #后一位不向当前位进位或借位
    dp[i][0]=dp[i+1][0]+abs(a-b)
    #后一位向当前位进位
    dp[i][0]=min(dp[i][0],dp[i+1][1]+abs(a+1-b))
    #后一位向当前位借位
    dp[i][0]=min(dp[i][0],dp[i+1][2]+abs(a-1-b))

    #dp[i][1]表示当前位向前进位
    dp[i][1]=dp[i+1][1]+abs(a-b)
    dp[i][1]=min(dp[i][1],dp[i+1][1]+abs(10-(a+1-b)))
    dp[i][1]=min(dp[i][1],dp[i+1][2]+abs(10-(a-1-b)))

    #dp[i][2]表示当前位向前借位
    dp[i][2] = dp[i + 1][2] + abs(a - b)
    dp[i][2] = min(dp[i][2], dp[i + 1][1] + abs(10+(a + 1- b)))
    dp[i][2] = min(dp[i][2], dp[i + 1][2] + abs(10+(a + 1 - b)))

#输出结果
print(min(dp[0][0],dp[0][1],dp[0][2]))

试题F:树上选点 (15分)

【问题描述】

        给定一棵树,树根为 1,每个点的点权为 。

        你需要找出若干个点 ,使得:

        1. 每两个点  互不相邻;

        2. 每两个点  与树根的距离互不相同;

        3. 找出的点的点权之和尽可能大。

        请输出找到的这些点的点权和的最大值。

【输入格式】

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

        第二行包含 n − 1 个整数  ,相邻整数之间使用一个空格分隔,分别表示第 2 至 n 个结点的父结点编号。

        第三行包含 n 个整数 ,相邻整数之间使用一个空格分隔,分别表示每个结点的点权。

【输出格式】

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

n = int(input())
fa = [0, 0] + list(map(int, input().split()))

v = [0] + list(map(int, input().split())) # 存1~n个结点的值
dep = [0] * (n + 1) # 每个结点的深度
dep_node = [[] for i in range(n + 1)] # 存每个深度中的结点编号
deep_max = 0 # 深度的最大值

for i in range(1, n + 1): # 求每个深度有哪些结点
    dep[i] = dep[fa[i]] + 1
    deep_max = max(deep_max, dep[i])
    dep_node[dep[i]].append(i)

dp = [[0] * 2 for i in range(n + 1)] # 表示i结点选或不选的情况dp[i][0/1]

state = [0, 0, 0] # [不选该层结点的最大值结点,选该层结点的最大值结点,选该层结点非最大值同父最大值结点]
for i in range(deep_max, 0, -1): # 从deep_max~1深度,自下向上
    for j in dep_node[i]: # j表示i深度的结点
        dp[j][0] = max(dp[state[0]][0], dp[state[1]][1])
        if fa[state[1]] == j: # 如果下一层的最大值结点是j的子结点, 则选择max(非j子结点的最大值, 不选的最大值结点)
            dp[j][1] = v[j] + max(dp[state[0]][0], dp[state[2]][1])
        else: # max(下一层的最大值结点, 不选的最大值结点)
            dp[j][1] = v[j] + max(dp[state[0]][0], dp[state[1]][1])
            
    state = [0, 0, 0]
    for j in dep_node[i]: # 求深度为i的dp[j][0]和dp[j][1]的最大值
        if dp[state[0]][0] < dp[j][0]:
            state[0] = j
        if dp[state[1]][1] < dp[j][1]:
            state[1] = j
            
    for j in dep_node[i]: # 求i深度下和选最大值结点非共同父结点的次最大值结点
        if fa[state[1]] != fa[j] and dp[state[2]][1] < dp[j][1]:
            state[2] = j

print(max(dp[1][0], dp[1][1]))

试题J:混乱的数组(25分)

【问题描述】

        给定一个正整数x,请找出一个尽可能短的仅含正整数的数组A使得A中恰好有x对i,j,满足Ai>Aj

        如果存在多个这样的数组,请输出字典序最小的那个。

【输入格式】

        输入一行包含一个整数表示x

【输出格式】

        输出两行

        第一行包含一个整数n,表示所求出的数组长度

        第二行包含n个整数Ai,相邻整数之间使用一个空格分隔,依次表示数组中的每个数。

 这样写的话,通过率为20%,特殊的数(如3,6,10,15,21,28......),n*(n-1)/2=x,求得。

这种情况不包含重复数字,但是这个例子启发了我,混分🤔

import os
import sys

import math
x = int(input())
n=1
while n*n-n-2*x<0:
  n+=1
print(int(n))
for i in range(int(n), 0, -1):
    print(i, end=" ")

通过率100%解 

import sys
from collections import Counter
from heapq import *
input = lambda: sys.stdin.readline().strip()
x = int(input())
if x == 0 :
    print(1)
else :
    def get(x) :
        return x * (x - 1) // 2
    i = 2
    while get(i) < x :
        i += 1
    ans = []
    n = i
    n -= 1
    a = x - get(n) + 1
    b = n + 1 - a
    for i in range(1 , a) :
        ans.append(i)
    for i in range(1 , b + 1) :
        ans.append(i)
    ans.sort(reverse=True)
    ans.insert(0 , a)
    print(n + 1)
    for x in ans :
        print(x , end = ' ')

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值