蓝桥杯2021省赛Python
创始人
2024-05-18 23:36:16
0

蓝桥杯2021省赛Python

不得不说2021的比2020的难

1.卡片

在这里插入图片描述

很明显,最先没的肯定是1或者0,我们只要统计到谁会消耗2022个1或者0就好了

if __name__ == '__main__':res1 = 0res0 = 0for i in range(1,100000):i = str(i)res1 += i.count('1')res0 += i.count('0')if res1 == 2022 or res0 == 2022 : breakprint(int(i)-1)# 3181

2.直线

在这里插入图片描述

两点式 (y1-y2)X + (x2-x1)Y + (x1y2-x2y1) = 0

那么我们只要把每两个点都遍历一遍,然后约分不同的加入进我们的集合就好了

(y1-y2) * x +(x2-x1) * y +( x1 * y2 - x2 * y1)=0 两点式求方程

def gcd(a,b):if b == 0: return aelse: return gcd(b,a%b)
if __name__ == '__main__':dian = []for i in range(20):for j in range(21):dian.append((i,j))res = set()for i in range(len(dian) - 1):x1,y1 = dian[i]for j in range(i+1,len(dian)):x2,y2 = dian[j]A,B,C = y2-y1,x2-x1,x1*y2-x2*y1k = gcd(gcd(A,B),C)  # 求三个数的最大公约数res.add((A/k,B/k,C/k))print(len(res))

3.货物摆放

在这里插入图片描述

首先我们可以看到他的那些因子一定是他可以除得尽的。先预处理出来,然后去遍历

注意一点的是如果你从1到n去预处理他的因子的话会很慢,所以我们可以只处理到sqrt(n)

import math
yin = []
n = 2021041820210418
# for i in range(1,n+1):  # 太慢了
#     if n % i == 0:
#         yin.append(i)
for i in range(1,int(math.sqrt(n) + 1)):if n % i == 0:yin.append(i)yin.append(n/i)print('over')res = 0
for i in yin:for j in yin:for k in yin:if i * k * j  == n:res += 1
print(res)

4.路径

在这里插入图片描述

很简单的一个动态规划问题,一个点到1的距离等于他前面21个任意一点到1的距离加上那个点到他的距离,我们只需要找到遍历前面21个点,找到最小值就好了。

这样一层一层最小下来,到最后一定是最小的。

def gcd(a,b):if b == 0: return areturn gcd(b,a%b)
def gbs(a,b):return a*b//gcd(a,b)  
inf = 1e9
dp = [inf] * 2022  # dp表示到1的距离
for i in range(1,23):dp[i] = ifor i in range(23,2022):for j in range(1,22):dp[i] = min(dp[i],dp[i-j] + gbs(i,i-j)) # 后面的到1的距离等于前面21中的一个到1的距离加上前面21个中一个到他的距离
print(dp[2021])

PS:好像math库里面有求最大公约数的函数,下次直接用就好了别自己定义了,怕大家手滑写错了

5.回路计算

在这里插入图片描述

你看总共就21个楼,我们可以用二进制来表示,比如状态11101就表示去了1,3,4,5楼。

设置一个dp,dp[i][j] 就表示在状态i下能到达j的总数量,你看这个状态去了就例如 i = 11101, j = 3,就是到达j+1 = 4楼的总数量(为什么要+1,因为我们用j = 0 表示到达了第一楼,后面我们是用i >> j & 1来表示能不能到达这个楼,所以就定义为j+1了,如果要j是到达j楼的话 ,i需要多开一位就更大了)

那么要怎么算到第四栋楼的数量呢,再看这个状态11101,发现他可以有1,3,5栋楼可以走,那么我们就遍历这三栋楼就好了,就是把到第四楼的那个i变成0,然后到达剩下三栋楼。

假设遍历到k ,dp[i][j] += dp[i - (1<

这样状态转移是对的,因为他每次用到的i都是比他小的,在之前肯定是遍历过的,不会出现漏的情况

 import math
n = 21
m = 1<<21
dp = [[0] * n  for _ in range(m+1)] # do[i][j]表示状态i到到达j的总数量
g =[[0]*n for _ in range(n)]  # g[i][j] 表示I能到Jfor i in range(1,n+1):for j in range(1,n+1):if math.gcd(i,j) == 1: g[i-1][j-1] = 1   
dp[1][0] = 1
# 如果要刚好dp[i][j] 表示第i个状态到第j个楼的话,要开22位的二进制,会更慢.所以我们j就表示J+1楼
for i in range(1,m):for j in range(n):if i >> j & 1:  # 判断j+1楼是否在里面for k in range(n):if i - (1 << j) >> k & 1 and g[k][j] == 1: #找到符合条件的kdp[i][j] += dp[i - (1 << j)][k]print(sum(dp[m-1]) - dp[m-1][0])  # 最后就是状态011111111111(21个1)到达不是1楼的就好了,因为每个楼都可以去1楼

6.时间显示

在这里插入图片描述

首先先找到那一天的毫秒数,然后再找小时数,以此类推,总共的毫秒数 - 小时的毫秒数 = 分钟数 + 减去小时和分钟剩下的毫秒数

n = int(input())
n = n%(24 * 60 * 60 * 1000) # 抛去前面N天的,剩下当天的毫秒数
hour = n // (60 * 60 *1000)
mins = (n - hour*60*60*1000) // (60 * 1000)
scent = (n - hour * 60 * 60 *1000 - mins * 60 * 1000) // 1000
print('%02d'%hour,end = ':')
print('%02d'%mins,end = ':')
print('%02d'%scent,end = '')

7.杨辉三角形

在这里插入图片描述

这题最开始我只写了一个时间复杂度高的,应该能得前面那个分,比较好理解,可以先看看。

 if __name__ == '__main__':n = int(input())if n == 1: print(1)res = 3 # 已经计算的个数li,l = [1,2],3  # 第三行的一半元素和行数while n not in li:res += len(li)*2 - l % 2li = [1] + [li[i] + li[i+1] for i in range(len(li) - 1)] + ([li[-1]*2] if l % 2 == 0 else []) l += 1print(res + li.index(n) + 1)

就是一行一行的去遍历,直到找到我们需要的

第二种是我觉得我这个太慢了,去看大佬的,不得不说太强了。。

思路参考:(156条消息) 备战蓝桥杯历年试题:杨辉三角形 省赛B组 Python详解_m0_62277756的博客-CSDN博客

但是其中还是有好像错误的点,我先在这里指一下,不对的话可以在评论区告诉我。。(当然代码没错)大佬在遍历斜行的时候,说从C(2i,i)找到C(2i,N),中有没有我们的答案,但我看了一下应该是从C(2i,i)到C(N,i)因为C(N,1)肯定是一个我们要的答案了。C(N,i)会大于他,因为这个点我当时想了蛮久的。。希望大家看的时候可以注意到这个点。能发现这个规律真的很厉害了

def c(a,b):res = 1i,j = a,1while j<=b:res = res * i / ji -= 1j += 1return int(res)def find(j,n):  # 在第j斜行找到n的位置l,r = 2*j,n # C(a,j)的a最小是2*j 最大是n,因为C(n,1)够了已经while l <= r:mid = (l+r)//2if c(mid,j) == n:print(int(mid*(mid+1)/2) + j + 1) # j+1不能在里面,否则会被忽略return Trueelif c(mid,j) > n:r = mid - 1else: l = mid + 1return Falseif __name__ == '__main__':N = int(input())for i in range(16,-1,-1):if find(i,N): break

8.左孩子右兄弟

0

这题其实我感觉跟我们学的左孩子右兄弟没什么关系啊,你只要把兄弟都变成你的右孩子,然后把你的孩子变成你的左孩子。那么我们就可以首先推出,如果你有3个孩子,那么以你为根的树高就是3+3个孩子的树高的最大值。### 因为你可以把三个孩子的其中一个变为左孩子,然后剩下两个其中一个变为那个左孩子的右孩子,然后剩下一个变为左孩子的右孩子的右孩子(画个图会好很多,建议去画画)然后我们只要找到三个孩子最高的树,让他当做最后一个孩子,那整体的树肯定就最高啦,并且会等于3+3个孩子树高的最大值,我们dfs搜索一下就好了。

没有孩子的高度就是0

ans = 0 
# f[u]以u结点为根的树的最大高度是u的子节点数量 + 各个子树的最大高度
# 其实就是看子树有多少个孩子,递归下去
def dfs(u): # global anstot = len(s[u])f[u] = totres = 0for i in range(tot):v = s[u][i]m = dfs(v)res = max(res,m)f[u] += resreturn f[u]if __name__ == '__main__':n = int(input())s = [[] for i in range(n+1)]for i in range(n-1):s[int(input())].append(i+2) # 输入 5 1 1 1 2  那就是 s[1] = [2,3,4] 表示 2,3,4是父节点是1f = [0]*(n+1)print(dfs(1))

9.异或序列

在这里插入图片描述

这题是偏难了我感觉,我的能力可能最多就做到这题。

可以思考一下,异或,所有数里面在二进制中的最高位比如是11,那么如果第11位是1的只有一个,那么先手肯定赢定了吧,他只要拿这个就好了,剩下的随便怎么异或,他最高位这个都不会变。

第11位有3个呢?那就要看剩下有几个了。这样想,假设总共有4个数,那么剩下一个数最高位不是1对吧。这样先手必输。因为如果你先手拿一个最高位是1的,我拿剩下那个最高位不是1的,你只能让我异或最高位是1或者你自己异或最高位是1,如果你让我异或最高位是1那么剩下的那个我就让你异或最高位是1,这样我的最高位是1你的最高位是0, 那么如果你先把最高位是0的那个给拿掉了,我拿一个最高位是1的,剩下两个数的最高位都是1(这里的最高位是全部数的最高位),你如果异或掉我的最高位,我再拿就好了,你如果要拿最高位去异或你自己的数,那么我下次再把你异或掉,你还是输。

但是如果剩下有偶数个就不一样了,我先手拿一个最高位是1的,如果你拿剩下的最高位不是1的,我也拿一个,因为是偶数,你拿一个我肯定也能拿一个,那么最后就是会剩下偶数个最高位是1的(因为我开始拿了一个),那么就是了,你异或我我就再拿一个,你异或你自己我就异或你,到最后肯定你最高位没有1,我最高位是1

第11位有偶数个呢?那没办法那就要看最高位的下一位,就是第10位了、

if __name__ == '__main__':t = int(input())for i in range(t):sum = 0max2 = 0list1 = [int(x) for x in input().split()]for i in range(1,len(list1)):sum ^= list1[i]max2 = max(max2,list1[i])  # 顺便记录下来最大的先 if sum == 0 :print(0)continuehigh = 1while high < max2:high = high<<1  # 找到最大的那个的最高位是多少while high > 0:temp = 0for i in list1[1:]:if i & high != 0: # 最高位和high相同temp += 1if temp == 1:print(1)break # 先手赢if temp %2 == 1: # 如果有奇数个最高位为1,那么就要看剩下的有几个if list1[0] % 2 == 1:  # n如果是奇数 减去奇数个最高位相同的,剩下的就是偶数个print(1)break # 除去最高位一样的那些,剩下的有偶数,就先手赢else: print(-1)break # 否则后手赢if temp %2 == 0:  #如果最高位有偶数位,则顺延到下一位high = high >> 1

PS: 是感觉说的有些乱了,不会的可以和我探讨一下

10.括号序列

在这里插入图片描述

这题确实是不会,搞了好久才勉勉强强搞懂。大家可以去看一下B站大雪菜的。。。我也是看他的,但有几个点我觉得我可以说一下,可能学习过程中会有些不理解

首先是状态转移方程,dp[i][j]表示的是前i个序列中,左括号比右括号多j个的方案数。

这里先考虑添加左括号,如果第i个序列上的位置是右括号,dp[i][j] = dp[i-1][j+1] + dp[i-1][j] + … + dp[i-1][0]

这是什么意思呢,就是说你在第i个序列为右括号了,那么我们可以在你的右括号前选择加左括号对吧,我如果选择加1个,你又要前i个序列左括号比右括号多j个,那么是不是前i-1个序列要左括号比右括号多j个? 因为我加了一个左括号,但第i个是右括号,这两个抵消了。如果我选择在这个右括号前面加3个左括号,那么方案数就会等于dp[i-1][j-2],想想,前面i-1个序列中,左括号比右括号多j-2个,然后又加了三个左括号一个右括号,是不是就是dp[i][j]了

如果第i个位置上是左括号那就什么都不用做了。

dp[i][j] = dp[i-1][j-1] 这里加了一个左括号,就会等于前面的i-1个序列 左括号比右括号多j-1个

然后就是我一直都想不明白的问题,为什么最后输出左括号的方案不是直接输出 dp[n][0],就是前n个序列中,左括号比右括号多0个,后面感觉是我自己想的太美满了,如果有一个序列是 (((),那么我们要添加最少的最括号能往哪里加?会好的选择就是不加左括号只加右括号,所以对于左括号来说,最后我们要选择的就是dp[4][2] ,并不是dp[4][0],只有在完美的情况下才会有dp[n][0]的出现,例如())),这样就肯定是dp[n][0],综上所述,我们输出的dp[n][i] ,i最小,一定是我们要的添加最少左括号的方案数。

右括号的话你翻个序再把左右括号互相变一下,继续用左括号的模板就好了

def func():dp = [[0] * (n+2) for _ in range(n+2)] # dp[i][j] 表示前i个序列,左括号比右括号多j个的方案数dp[0][0] = 1for i in range(1,n+1):if s[i-1] == '(':for j in range(1,n+1):dp[i][j] = dp[i-1][j-1]else:dp[i][0] = (dp[i - 1][0] + dp[i-1][1]) % modfor j in range(1,n+1):dp[i][j] = (dp[i][j-1] + dp[i-1][j+1]) % mod # 0特判是因为会出界for i in range(n+1):if dp[n][i]:  #找前n个中左括号比右括号多的数最少,表示我们添加的也最少return dp[n][i]return -1
if __name__ == '__main__':s = list(input())n = len(s)mod = 1e9 + 7left = func()s.reverse()  # 从左往右看是填左括号,右往左是填右括号# 但是因为我们func是按左括号写的,所以还需要将左括号和右括号对调一下,这样我们就不用重新写一个函数for i in range(n):if s[i] == ')':s[i] = '('else:s[i] = ')'right = func()print(int(left*right % mod))

这题还是好难我感觉,上考场我肯定不会做。。。大家加油

相关内容

热门资讯

安卓只恢复系统应用,重拾系统流... 你有没有遇到过这种情况?手机突然卡顿,或者某个应用突然罢工,你一气之下,直接开启了“恢复出厂设置”大...
安卓系统出现支付漏洞,揭秘潜在... 你知道吗?最近安卓系统可是闹出了不小的风波呢!没错,就是那个我们每天离不开的安卓系统,竟然出现了支付...
苹果换了安卓系统恢复,体验变革... 你有没有遇到过这种情况?手机里的苹果突然变成了安卓系统,而且还是那种让你摸不着头脑的恢复模式。别急,...
安卓怎么卸载系统app,轻松告... 手机里的系统应用越来越多,有时候真的让人眼花缭乱。有些应用虽然看起来很实用,但用起来却发现并不适合自...
安卓系统查看步数,揭秘日常运动... 你有没有发现,每天手机里的小秘密越来越多?今天,咱们就来聊聊安卓系统里那个悄悄记录你每一步的小家伙—...
安卓系统未来会不会,未知。 你有没有想过,那个陪伴我们手机生活的安卓系统,它的未来会怎样呢?想象每天早上醒来,手机屏幕上跳出的信...
安卓系统怎么设置截图,轻松捕捉... 亲爱的手机控们,你是不是也和我一样,有时候想记录下手机屏幕上的精彩瞬间呢?别急,今天就来手把手教你如...
安卓系统下载软件安装,安卓系统... 你有没有发现,手机里的安卓系统就像一个巨大的宝藏库,里面藏着各种各样的软件,让人眼花缭乱。今天,就让...
安卓10系统转移程序,轻松实现... 你有没有想过,当你从一台安卓手机升级到安卓10系统后,那些珍贵的照片、联系人、应用和数据怎么才能无缝...
安卓电脑强制重启系统,原因解析... 你有没有遇到过这种情况?你的安卓电脑突然间就强制重启了,屏幕上闪过一行行代码,你还没来得及保存文件,...
安卓怎么降低系统耗电,深度解析... 手机电量总是不够用,是不是你也和我一样,每天都要担心手机没电呢?别急,今天就来教你怎么给安卓手机降耗...
安卓系统的总体框架,架构与核心... 你有没有想过,你的手机里那个神奇的安卓系统,它到底是怎么运作的呢?今天,就让我带你一探究竟,揭开安卓...
谁的安卓系统好,谁家的安卓系统... 说到安卓系统,这可是个热门话题呢!你有没有想过,这么多安卓手机品牌,哪个的操作系统最让你心动?今天,...
安卓系统信付通,安全无忧的移动... 你知道吗?在安卓手机的世界里,有一个超级好用的支付工具,它就是信付通。今天,就让我带你来全方位了解一...
小米官方系统安卓包,深度解析与... 亲爱的数码爱好者们,你是否曾为手机系统而烦恼?市面上那么多手机品牌,各种操作系统让人眼花缭乱。今天,...
自制安卓手机双系统,自制安卓手... 你有没有想过,自己的手机可以同时运行两个操作系统呢?没错,就是那种安卓手机双系统!听起来是不是很酷?...
小米安卓系统怎么设置,科技前沿... 小米手机的用户们,是不是觉得安卓系统有点复杂,设置起来有点头疼呢?别担心,今天就来手把手教你如何轻松...
点歌系统支持安卓系统么,安卓用... 你有没有想过,在手机上点歌听歌,是不是也能像在KTV里那样随心所欲呢?现在,就让我来告诉你一个超级酷...
原版安卓系统刷机,解锁无限可能 你有没有想过,你的安卓手机其实可以焕然一新?没错,就是那种原汁原味的安卓系统,让你的手机重新找回当初...
欧尚改装安卓系统,打造智能驾驶... 你有没有想过,你的欧尚汽车其实也可以变身成为智能座驾呢?没错,就是那个你每天上下班的伙伴——欧尚,现...