14届蓝桥杯Python总结_请求出在 12345678 至 98765432 中,有多少个数中完全不包含 2024 。 完全不包

收集整理了一份《2024年最新Python全套学习资料》免费送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img



既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Python知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来

如果你需要这些资料,可以添加V无偿获取:hxbc188 (备注666)
img

正文

        j += 1
    if j == 4:   # 说明完全包含2023
        return True
return False

for i in range(12345678,98765433):
if not find(i): # 注意这里要的是完全不包含2023,
ans += 1 # 要取反加not,我这里没仔细看,结果就是反向答案
print(ans)

print(98765433 -12345678 - 460725) # 用反向答案求答案。。。

反向答案 460725

答案 85959030




---


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


![](https://img-blog.csdnimg.cn/81f23d1d34884ca2afe8b1f08fa83148.png)


**代码及思路:**



> 
> 这道题在比赛时,我首先看了一眼没有思路就跳过去了,再后来要交卷了,想起来这个填空题还没有写,匆忙之下就想着2023有2023个,最后加一起的时候应该也是最多的,那么谁加谁等于2023,我很直接的想到了1011+1012,有1011个,然后加上2023个交卷了。事后在看这个突然发现答案与我擦肩而过,既然1011+1012=2023,那么1010+1013 = 1009+1014 = ... = 1 + 2022,都满足等于2023,且个数依次就是从1加到1011个,最后再加上新的2023就是答案了???
> 
> 
> 不,这只是比较直接的想法,在已有的硬币中有1~2023,生成的硬币在这里面的话和为2023最后是最多的 ,但可以生成硬币值大于2023的新的硬币,这样就是另一种情况了。
> 
> 
> 



> 
>  **根据两个硬币加和为新硬币值,可以发现最后加的一次为 (新硬币值-1) / 2,以2023为例,从1+2+..+1011, 最后加到了1011结束,类推之后,我们暂且把最后加和的新硬币值设为NewSum,加和的最后一个硬币值设为End,加和的起始硬币为Start,则有NewSum = End \* 2 + 1,又因为新硬币值为Start+2023,有NewSum = Start + 2023,又因为最后的种数是以Start为首项,1为公差的等差数列的和,项数共有End - Start + 1项。**
> 
> 
> **可以得到和为NewSum的种数为 Sn = (End - Start + 1) \* (Start + End) / 2**
> 
> 
> **结合NewSum = End \* 2 + 1,NewSum = Start + 2023。**
> 
> 
> 我们可以得到关于End的一个方程,![Sn = -\frac{1}{2} * (3End^{2} - 8091End + 2022*2023)](https://latex.csdn.net/eq?Sn%20%3D%20-%5Cfrac%7B1%7D%7B2%7D%20*%20%283End%5E%7B2%7D%20-%208091End%20+%202022*2023%29)
> 
> 
> 是一个开口向下的二次函数,化简内部关键部分得,![Sn = -\frac{3}{2} * (End - 1348.5)^{2} + \partial](https://latex.csdn.net/eq?Sn%20%3D%20-%5Cfrac%7B3%7D%7B2%7D%20*%20%28End%20-%201348.5%29%5E%7B2%7D%20+%20%5Cpartial)
> 
> 
> 可知当End为 1348.5 时种数取得最大值,因为只能取整数,则End取1348和1349都行。
> 
> 
> 代入方程得Sn = 682425
> 
> 
> 



ans = 2023 # 现有的2023个
for i in range(1,1012):
ans += i # 合成的2023的个数
print(ans) # 513589



ans = 0

当我们化简完式子就知道End取什么值了,不化简用代码来枚举也是同样的

for End in range(1012,2023): # 由公式知,end是变量,end使Sn最优
NewSum = End * 2 + 1 # 大于2023的新硬币值
Start = NewSum - 2023 # 起始的第一个数
Sn = (End - Start + 1) * (Start + End) // 2 # 数列求和公式
if Sn > ans:
ans = Sn
else:
print(ans) # 682425
break




---


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


![](https://img-blog.csdnimg.cn/67d6e419b7b94b5c8a84ef8a543b88a7.png)


**代码及思路:**



> 
>  正确理解:根据pi-p(i-1)>=2,这里pi 是原字符串的下标,即在子串中两个相邻的字符在原字符串中的下标至少要相邻2.要获得子串的最大值,并且满足条件,可以使用递推,即子序列中后一位的最大值由前一位最大值加上本身的值得到。使用动态规划进行动态递推。创建dp数组,令 dp[i] 表示以第 i 个字符结尾的松散子序列中的最大价值,定义一个指针K来表示满足 pi − pk ≥ 2 的最大的位置,通过转移方程dp[i] = dp[k] + val[s[i]]更新最大值。
> 
> 
> 



def getmax_value(s):
n = len(s)
# res = “”
dp = [0] * n # 创建dp数组,令 dp[i] 表示以第 i 个字符结尾的松散子序列中的最大价值
val = {chr(i+97): i+1 for i in range(26)} # 创建一个字母:值的字典,便于获取字母的值
# print(val)
k = -1 # 定义一个指针K来表示满足 pi − pk ≥ 2 的最大的位置,通过转移方程dp[i] = dp[k] + val[s[i]]更新最大值
for i in range(n):
if i == 0:
dp[i] = val[s[i]] # 把第一个字母的价值赋值
elif i == 1:
dp[i] = max(val[s[i]], dp[i-1]) # 保存最大值
else:
while k < i-2 or (k >= 0 and s[k+1:k+3] != s[i-1:i+1]): # k == i - 2跳出循环
k += 1 # k来记录满足pi-pk >= 2的最大位置,(逐个递增)
# res += s[k]
dp[i] = dp[k] + val[s[i]] # 递推,当前位置值最大值为前一个满足距离条件的最大值+现在的值
dp[i] = max(dp[i], dp[i-1]) # 现在的位置更新最大值,保证k位置最大值是k其前面的最大值,
# print(res)
return dp[-1] # 最后为整体最大值

s = input() # azaazaz
ans = getmax_value(s)
print(ans)



> 
> 错误理解:t是原序列的子序列,就是其中任意一部分。然后看定义就是说松散子序列满足当前字母的价值减去前一个字母的价值要大于等于2.,然后就暴力循环判断,测试用例只有一个,看着答案对了,就没多想。。。 
> 
> 
> 



s = input() #“azaazaz”
ans = “”
res = 0
length = len(s)
for i in range(1,length):
if ord(s[i]) - ord(s[i-1]) >= 2: # 满足条件,说明是子序列中的一个
ans += s[i]
res += ord(s[i]) - 96 # 价值从1开始

print(ans) # zzz

print(res) # 78




---


#### **试题 D: 管道(10分)**


![](https://img-blog.csdnimg.cn/e22579febf3544128e20e82e15c38993.png)


![](https://img-blog.csdnimg.cn/dc151b058b8745979e2088299c0a0b90.png)


![](https://img-blog.csdnimg.cn/c15564cb972448a0961bd52df6005e3c.png)


**代码及思路:**


首先吐槽一下,为什么测试样例只给一个啊,我写出来,为了测试一下样例,把代码中的范围缩小了下,结果就是缩小了没有改回去,真正测试肯定不通过的(还是怪自己粗心,白忙活了。。。)



> 
> **这道题要求管道中每一段都检测到有水流,然后求这个条件的最早时间,在由管道每一段它根据时间不同,它周围的某一区间管道也会检测到,根据这种与区间相关的性质,我们可以想到用差分数组和前缀和来进行操作区间。如下图,构造一个区间数组,初始状态为0 ,然后对每一次时间的值,根据给的区间公式 Li-(Ti-Si)~ Li+(Ti-Si)进行求出区间左边和右边,这就可以用到差分数组,在当前t时间时对每个阀门进行求区间,然后对区间加一,当最后dp数组中从起始位置1到管道最右边都为1时,说明每段都检测到了水流,输出时间t,退出循环。**
> 
> 
> **这里时间T需要我们自己寻找,那么就有遍历查找和二分查找两种方法数据量太大,暴力是过不完的。**
> 
> 
> 


![](https://img-blog.csdnimg.cn/6b952acefd2a494c8d56e02f6884b7fd.png)



> 
> 下面是暴力解的思路:
> 
> 
> 在此基础上加上二分可以降低遍历时间 t 的时间复杂度O(n)为O(logn)
> 
> 
> 



n,len = map(int,input().split())
L,S = [],[]
for i in range(n):
a,b = map(int,input().split())
L.append(a)
S.append(b)
minS = min(S) # 直接让t从最小的Si开始,就能开始检测了

for t in range(minS,100000000): # 就是这里t的范围一定要大,。。
dp = [0] * (len+2) # 构造dp数组记录状态,我们定义数组管道长度区间中全为1时,t即为答案
# 构建差分数组
for i in range(n, 0, -1):
dp[i] -= dp[i - 1]
for i in range(n): # 求一个阀门的左右区间
if t >= S[i]:
a = L[i] - (t-S[i])
b = L[i] + (t-S[i])

        if a < 0:   # 最左边不能为负数
            a = 0
        if b > len:  # 最右边为管道长度
            b = len
        # print(a,b)
        # 转换加减(区间加减-->端点加减)
        dp[a] += 1
        dp[b+1] -= 1
# 前缀相加(前缀和公式)
for i in range(1,len+2):
    dp[i] += dp[i-1]
# print(dp)  # 查看dp数组
if sum(dp[1:len+1]) == len:  # 区间全为1说明完成
    print(t)
    break


输入

3 10
1 1
6 5
10 2

查看dp数组

[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0]
[1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]

ans

5



> 
>  下面是加上二分进行优化后的代码:
> 
> 
> 我们就是要找一个时间 t ,满足 t 时刻刚好覆盖区间,用二分查找这样的时间 T 会比遍历快很多。
> 
> 
> 



“”"
3 10
1 1
6 5
10 2
“”"

n,len = map(int,input().split())
L,S = [],[]
for i in range(n):
a,b = map(int,input().split())
L.append(a)
S.append(b)

def checkT(t): # 返回当前时间T的区间状态和
dp = [0] * (len+2) # 构造dp数组记录状态,我们定义数组管道长度区间中全为1时,t即为答案
# 构建差分数组
for i in range(n, 0, -1):
dp[i] -= dp[i - 1]
for i in range(n): # 求一个阀门的左右区间
if t >= S[i]:
a = L[i] - (t-S[i])
b = L[i] + (t-S[i])

        if a < 0:   # 最左边不能为负数
            a = 0
        if b > len:  # 最右边为管道长度
            b = len
        # print(a,b)
        # 转换加减(区间加减-->端点加减)
        dp[a] += 1
        dp[b+1] -= 1
# 前缀相加(前缀和公式)
for i in range(1,len+2):
    dp[i] += dp[i-1]
# print(dp)  # 查看dp数组
return sum(dp[1:len+1])  # 返回该时间的区间和

l,r = 1, 100000000
while l < r:
mid = (l+r) // 2
if checkT(mid) < len: # 时间不够,没覆盖完
l = mid + 1
elif checkT(mid) > len: # 时间太大,不是刚好的时候
r = mid
else: # 此时时间 t 刚好完全覆盖区间范围
print(mid)
break




---


#### **试题 E: 保险箱(15)**


![](https://img-blog.csdnimg.cn/fb98a758a5f546489efea55b89cd7f8b.png)


![](https://img-blog.csdnimg.cn/0b275a1fe51044c5acefd74b5bbb83b2.png)


**代码及思路:**



> 
> 这道题就是暴力模拟了,从最后一位数字进行比较,然后判断经过加还是减最小步骤相等,然后判断有进位么,有借位么,有的话更新数字,然后继续比较,直到两数相等,累记步骤和。
> 
> 
> 



### 最后

不知道你们用的什么环境,我一般都是用的Python3.6环境和pycharm解释器,没有软件,或者没有资料,没人解答问题,都可以免费领取(包括今天的代码),过几天我还会做个视频教程出来,有需要也可以领取~  

给大家准备的学习资料包括但不限于:  

Python 环境、pycharm编辑器/永久激活/翻译插件  

python 零基础视频教程  

Python 界面开发实战教程  

Python 爬虫实战教程  

Python 数据分析实战教程  

python 游戏开发实战教程  

Python 电子书100本  

Python 学习路线规划

![](https://img-blog.csdnimg.cn/d29631674929476f9c3b30f7ff58dff0.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZlaTM0Nzc5NTc5MA==,size_16,color_FFFFFF,t_70)




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**如果你需要这些资料,可以添加V无偿获取:hxbc188 (备注666)**
![img](https://img-blog.csdnimg.cn/img_convert/445d4f197d6d00ae7b0fe1011cdb83b1.png)

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
ng?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZlaTM0Nzc5NTc5MA==,size_16,color_FFFFFF,t_70)




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**如果你需要这些资料,可以添加V无偿获取:hxbc188 (备注666)**
[外链图片转存中...(img-Wb9uEoI0-1713787164074)]

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值