2021年蓝桥杯|省赛|python组|题目解析+代码

一、卡片问题

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Ya354Os5Lq_5LiL,size_20,color_FFFFFF,t_70,g_se,x_16

【题目解析】
由于数据量比较小,直接暴力枚举即可,依题意可以很快知道,卡片最先用完的数是“1”,因此遍历足够多的数,将每个数转换成字符类型,计算每个字符里面“1”的个数。

注意:“1”用完可能不是临界条件,有可能下一个数字不需要用到“1”.(本题刚好下一个数就要用到)

【代码实现】

count=0
for i in range(1,200000):
    t=str(i)
    for j in range(len(t)):
        if t[j]=="1":
            count=count+1
            if count==2022:
                print(i-1)
                break


【运行结果】

3181

二、直线

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Ya354Os5Lq_5LiL,size_20,color_FFFFFF,t_70,g_se,x_16

【题目解析】

  • 不同条直线的定义是截距或者斜率不同,所以我们只需要把所有的点两两组合,算出所有的斜率和截距,再利用集合去掉重复的元素,剩下的数量就是不同直线的数量。
  • 对于坐标的生成,可以用二维数组,也可以直接用四重for循环(数据量很小的情况下)。

接下来话不多说,直接上代码。

【代码实现】

re=set()
for x1 in range(20):
    for x2 in range(20):
        for y1 in range(21):
            for y2 in range(21):
                if x1==x2:
                    continue
                k=(y2-y1)/(x2-x1)
                b=(x2*y1-x1*y2)/(x2-x1)
                if (k,b) not in re:
                    re.add((k,b))
print(len(re)+20)

【运行结果】

40257

三、货物摆放

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Ya354Os5Lq_5LiL,size_20,color_FFFFFF,t_70,g_se,x_16

 【题目解析】

法一:直接三层for循环遍历每一个数,计数每一种可能的总个数。但是,本人亲测,跑了两小时没跑出来。。。。。

法二:求出n的所有因子,再建立三层循环,可以大大降低算法的复杂度。

虽然直接提交还是超时了,但是这道题是填空题,只要运行后直接print()就好了。如果有更好的方法也欢迎在下方评论区告诉我呀!

【代码实现】

n = 2021041820210418 
str1 = set()   # 用于存放因数,去重
for i in range(1,int(n ** 0.5)+1):     #因数求前面的就好,后面的与前面的一样,即3*6与6*3
    if n % i == 0: # 整除
        str1.add(i) # 将其存入到因数集合中
        re = int(n/i)
        if re != i:     
            str1.add(re)

#计算所有符合要求的组合
N = 0 
for i in str1:
    for j in str1:
        for k in str1:
            if i * j * k == n:
                N = N+1
print(N)

【运行结果】

2430

四、路径

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Ya354Os5Lq_5LiL,size_20,color_FFFFFF,t_70,g_se,x_16

 【题目解析】

采用动态规划,遍历i到i+21直接所有路径的最小值,然后不断迭代就可以得到最优解。

  • gcd()     内置求最大公约数函数
  • i*j//math.gcd(i,j)     最小公倍数

【代码实现】

import math
# gcd()求最大公约数
dp=[1000000000]*(2021+1)
dp[1]=0
for i in range(1,2021):    #起点
    for j in range(i+1,i+22):  # i与i+1,i+2,.....i+21的路径长度
        if j>2021:
            break
        dp[j]=min(dp[j],dp[i]+i*j//math.gcd(i,j))     #不同路径到dp[j],选出最短的路径   
print(dp[2021])

五、回路计数

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Ya354Os5Lq_5LiL,size_20,color_FFFFFF,t_70,g_se,x_16

 暂时不懂

六、时间显示

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Ya354Os5Lq_5LiL,size_20,color_FFFFFF,t_70,g_se,x_16

【题目解析】 

  • 毫秒先化为秒
  • 时应该小于24
  • 不足两位要补零

【代码实现】

a=(int(input()))//1000    #化为秒
n=(a//3600)%24   #小时数要小于24小时
m=(a%3600)//60    
k=(a%3600)%60
print("{:02d}:{:02d}:{:02d}".format(n,m,k))

七、杨辉三角

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Ya354Os5Lq_5LiL,size_20,color_FFFFFF,t_70,g_se,x_16

【省流版本】
如果直接用暴力枚举的话,需要求出每一行的全部数字,然后判断每一行中是否存在该整数,思路可以,但是时间复杂度太大,只能拿30%。如果根据二项式定理,找出从哪一行开始只需要遍历前三个数,然后利用求和公式直接计算答案,就可以大大减少时间复杂度。

【题目解析】
首先介绍一下杨辉三角的性质:

1、每个数等于它上方两个数的和。

2、左右对称(说明最先出现的数一定在左边)

3、第n行有n个数,前n行就有(n+1)*n/2个数

4、n+1行的数是(a+b)^n展开后各项的系数

所以,由性质4可得,第n行的m个元素为C(n-1,m-1),由于1 ≤ N ≤ 1000000000,每一行第四个数为N*(N-1)*(N-2)/6,粗略计算,当N>1900时,第四项就大于1000000000了,所以说,从第1901行开始,N若是第一次出现,只可能出现在第二第三项。

因此,在前1900层时,可以直接使用暴力枚举,在判断是否在该层,若不在前面1900层,先粗略估计N所在的层数(先计算在第三项时,因为若存在,就会先出现)int((N*2)**0.5),这时,就只需要判断三种情况:①N在该层;②N在下一层;③N在N+1层。

最后计算在第几个数上,分为三种情况:

1、在前1900层时,(c*c+c)//2+j+1 ,在c+1层的第j+1个数时(j是在列表中的下表,因此要加1)

2、在1900层之后且是第三项时,(k*(k+1))//2+3,第k+1行

3、在1900层之后且是第二项时,(N*(N+1)//2)+2,第N+1行时

【代码实现】

N=int(input())
n=[1]   #第一层
c=1     #层数
if N==1:
    print(1)
else:
    #由于第1900层开始,N只会出现在第二个或第三数字上,所以1900开始,不需要求全部
    while c<1900:
        n = [1]+[n[j]+n[j+1] for j in range(len(n)-1)]+[1]    #杨辉三角递推公式
        if N not in n[1:len(n)-1]:   #判断N是否在c层上
            c=c+1
        else:
            break         
    if c==1900:
        k=int((N*2)**0.5)  #粗略计算出现的层数 
        #N出现在第三个数上
        while (k*(k-1))//2<N:
            k=k+1
        if (k*(k-1))//2==N:
            print((k*(k+1))//2+3)
        #N出现在第二个数上
        else:
            print((N*(N+1)//2)+2)    # N会出现在第N+1层       
    #N在前1900层上时        
    for j in range(len(n)):
        if n[j]==N:
            print(((c*c+c)//2)+j+1)   
            break

八、左孩子右兄弟 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Ya354Os5Lq_5LiL,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Ya354Os5Lq_5LiL,size_20,color_FFFFFF,t_70,g_se,x_16

九、异或数列 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Ya354Os5Lq_5LiL,size_20,color_FFFFFF,t_70,g_se,x_16

十、括号序列 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Ya354Os5Lq_5LiL,size_20,color_FFFFFF,t_70,g_se,x_16

  • 8
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冷烬亿下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值