2020蓝桥杯省赛第二场Python组题解(不太全,有的不会,有的不记得了)
A 门牌制作
题目描述:
大概就是说制作门牌号是一个一个数字网上贴的,比如1017需要2个1,1个0,1个7。然后问你制作1到2020一共需要多少个数字2
结果:624
题解:
# 没啥好说的直接字符串查找
s=0
for i in range(1,2021):# 遍历1到2020
s+=str(i).count('2')# 查找有多少个2
print(s)
B 2020?
题目描述:第二题好像是数2020个数那个吧?
就是给你一个300*300的2和0的字符串,问你他包含多少个2020(这个不能用count的,因为202020是2个)
只能从左往右横着数或者从上往下竖着数,或者从左上往左下谢着数
比如下面这个有7个,横着1个,竖着3个,斜着3个。
2 0 2 0 0 2
0 0 0 0 2 0
0 0 2 0 2 2
0 0 0 0 0 0
0 0 0 0 2 0
0 0 0 0 0 0
(我空格是为了方便查看,真实的里边没有空格。)
结果: 这谁记得啊,我又没有他的数据,呜呜呜
题解:
# 这题,这题我是把它横着拆成1个列表,竖着拆1个,斜着拆1个。。还挺费时间的。
def count(s):
s1=0
for i in range(3,len(s)):# 0,1,2,3->1,2,3,4一个个的排查
if s[i-3:i+1]=='2020':s1+=1# 字符串切片s[0:4]就是0,1,2,3
return s1
with open("2020.txt",'r')as f:
a=f.readlines()# 横着的数列
n=len(a)# n行
for i in range(n):# 因为他最后是带一个
符的,我把它消掉。
a[i]=a[i][:-1]
m=len(a[0])# m列
b=['' for i in range(m)]# b来竖着存这些数,所以有列条字符串
for i in range(m):
for j in range(n):
b[i]+=a[j][i] # b[0]+=a[0][0]、a[1][0]、a[2][0]、...
c=[]# 斜着的最麻烦了。。我的办法是以对角线为分界,写两个循环。
for i in range(n-1,-1,-1):# 打算先从左下角找到左上角
s=''
for j in range(n-i):# 每次只添加n-i个,即从1个到n个长度递增(因为长宽相等)
s+=a[i+j][j]# 也就是第一次(n-1,0),第二次(n-2,0和n-1,1)
c.append(s)
for j in range(1,n):# 换j从0到n遍历了,i初始不变
s=''
for i in range(n-j):
s+=a[i][i+j]# (0,1)(1,2),...,(n-2,n-1),(0,2)(1,3),...,(0,n-1)
c.append(s)
s=0
for i in a:
s+=count(i)
for i in b:
s+=count(i)
for i in c:
s+=count(i)
print(s)# 把3个列表都遍历一遍,找出所有2020,用我上面那个例子就是输出7没错啦!
C 蛇形数列
题目描述:
数列大概长这样:就是右走2个,然后斜着走到头,再下走2个,然后斜着走到头,再右走2个,…循环
1 2 6 7 15 16 ..
3 5 8 14 17 ..
4 9 13 18 ..
10 12 19 ..
11 20 ..
21 ..
..
然后问你,第20行第20列是啥。(下标从1开始)
结果:761(我咋好像当时填的685,难道我还填错了?哭、、了)
题解:
# 我真的是一点点模拟的他怎么走找的啊,后来听他们说有规律。
# 就是[1][1]是1,[2][2]是5,[3][3]是13,[4][4]是25你会发现1和2差4,2和3差8,3和4差12。。。
# 因为i和j相同简化成一维。于是有dp[1]=1,dp[i]=dp[i-1]+4*(i-1)
dp=[0,1]
for i in range(2,21):
print(i-1,dp[-1])
dp.append(dp[-1]+4*(i-1))
print(len(dp)-1,dp[-1])
D 跑步训练
题目描述:
一个小孩,从2000年1月1日到2020年10月10日每天都跑1千米,而周一或月初(每月1号)他会跑2千米。如果既是周一也是月初也是跑2千米。问他一共跑了多少千米。
结果:8879
题解:
# 这题我也哭死啊,都算出来周一或月初一共有多少天了,直接交了,忘了加每天都要跑的1km了。。。(但愿是我记错了,呜呜呜)
# 哦,这里说一个小技巧,你可以用dir(datetime)来查看他的方法和类啥的。
# 还有idle的help里有一个python doc也是可以打开的。(我就是现查的datetime类的使用方法查了好久,导致忘了题目。呜呜呜)
from datetime import datetime as dt
from datetime import timedelta as td
time1=dt(2000,1,1)# 创建起始时间对象
time2=dt(2020,10,1)# 创建结束时间对象
day=td(days=1)# 创建增加一天用的对象。(注意这里是td,是timedelta)
s=0
while time1<=time2:# 时间是可以直接比较的
if time1.day==1 or time1.weekday()==0: s+=1# weekday()是方法,[0-6],day是属性
s+=1# 不是特殊的也要加1,我当时好像忘加了呜呜呜
time1+=day# datetime对象只能与timedelta对象进行运算,返回datetime对象。
print(s)
E 排序,还是叫什么来着
题目描述:
就是他说如果只交换相邻的元素的话,冒泡排序的交换次数是最少的。比如lan只用交换a和l,就是1次。
然后让你找排序时要交换100次的最短的字符串中字典序最小的那个,然后他把可以有重复元素那句删了。(我不知道是不是代表不能有重复元素)
结果:这题我不会,把我的发一下吧,找了长度15的一个字符串。
jonmlkihgfedcba
题解:
瞎试的没题解。
F 统计成绩?
题目描述:
前两道简单编程题我都没啥印象了。可能顺序也搞混了。这题就是,60分及以上及格,85分及以上优秀,让你求及格率和优秀率。输出的时候要65%这种格式,四舍五入。
题解:
n=int(input())# n个学生
su,ji,you=0,0,0# 三个统计
for i in range(n):
x=int(input())
su+=1
if x>=60: ji+=1
if x>=85: you+=1
print(f'{ji*100/su:.0f}%')# 我用格式化字符串输出的。
print(f'{you*100/su:.0f}%')
G 单词分析
题目描述:
哈哈哈,看了隔壁Java组题解想起来这道题了,(果然Python,Java,C组的题目重合率很高23333)
言归正传,这道题的大意就是统计一个只包含小写字母的字符串中出现最多的是哪个,并输出次数和字母是谁。次数相同的话输出字典序最小的。
样例:
输入:
lanqiao
输出:
2
a
输入:
longlonglongistoolong
输出:
6
o
题解:
s=input()
m1,m2=0,0 # m1代表最多的次数,m2代表对应的字母
for i in range(25):
c=chr(97+i) # 遍历a-z
t=s.count(c) # 查找字母出现的次数
if t>m1: # 这里要大于才可以,等于也不换,才能保证是字典序最小的。
m1=t
m2=c
print(m1)
print(m2)
H 捡水果还是啥的?
题目描述:
就是一个小孩一层层地捡水果,每层只能往左下和右下最近的那个走,问最多能捡几个。往左走和往右走的次数相差不能超过1。哎,这题也挺可惜的,我当时没读懂题。。还写了贼久。。
样例(我自己编的):
输入:
4
7
9 10
9 6 9
2 6 10 9
输出:
36
提示:
左走就是往下,右走就是往右下。
样例是右右下7+10+9+10=36。
题解:
因为没读懂题这题我纠结了好久。比完赛才做出来这道题。。。
# 下面会同时写递归版(超时)和动态规划版两种解法。(递归版用来对拍判断正确与否的)
ss=0
def dfs(i,j,l,r,s):
# 递归出口:如果到了最后一层
if i==n-1:
# 如果左走右走次数相差超过1,直接返回
if abs(l-r)>1: return
# 否则,ss取较大的那个。(因为s从0开始,所以每次要加上a[i][j])
global ss
ss=max(ss,s+a[i][j])
return
# 递归左走和右走的情况,左走就是i+1,j不变,l+1,
dfs(i+1,j,l+1,r,s+a[i][j])
# 右走就i+1,j也+1,r+1.s统一都要加a[i][j],代表到当前这一步的总和。(而不是到下一步的和)
dfs(i+1,j+1,l,r+1,s+a[i][j])
# 用的是自造的例子,最大n为100
for ww in range(16):
with open(f"{ww+1}.in",'r')as f:
# --------录入数据
n=int(f.readline())#int(input())
a=[[] for i in range(n)]# 初始化n个列表
for i in range(n):# 每个列表直接继承每一行的输入(好像直接等于也成,捂脸)
a[i].extend([*map(int,f.readline().split())])#([*map(int,input().split())])
# --------计算结果
# 递归版解法,暴力对拍用,到我的第4个例子就算不动了,大概也就到n=三四十吧?
# 每次到最后一层的时候比较ss和结果谁大,ss取大的,最后输出ss。
# ss=0
# 5个参数分别是i,j,l,r,s.i和j是坐标,l和r是左右走的次数,s是和的结果。
# dfs(0,0,0,0,0)
# print(ss)
# 下面是动态规划版解法
# 初始化一个形如[[0],[0,0],[0,0,0],...]的dp数组
dp=[[0 for j in range(i+1)] for i in range(n)]
dp[0][0]=a[0][0] # 起点是a[0][0]
# 遍历每一层
for i in range(1,n):
# 如果j是0的话,只可能是从上一层的0走下来的,所以直接dp[i-1][0]+a[i][0]就是这层结果了。
dp[i][0]=dp[i-1][0]+a[i][0]
# 之后j遍历[1,i-1]
for j in range(1,i):
# 这个时候,就有两种可能了,可能是左上往右走下来的,也可能是正上往左走下来的。
# 就要比较得出他们中较大的那个再加a[i][j]。
dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+a[i][j]
# 同样每层的最后一个只可能是上一层最后一个走下来的。
dp[i][i]=dp[i-1][i-1]+a[i][i]
# 你可能会想,如果这样的话,到最后一层的时候,你怎么知道他是左右各走了几次呢?
# 这个其实是又规律的。因为他左右相差不能超过1,所以他最多只可能走到下面的两个点。
# 还要分n是奇数还是偶数。如果n是奇数,他左走和右走的次数是一样的。(因为第一层是0步嘛)
# 所以此时他只可能走到dp[-1][n//2]。(因为左走j不变,右走j+1,右走一半次,无论如何都是走到中间。)
if n%2: print(dp[-1][n//2])
# 而如果n是偶数的话,只可能是左走多一次或者右走多一次,右走多一次就是n//2,右走少一次就是n//2-1
else: print(max(dp[-1][n//2],dp[-1][n//2-1]))
I (未解)平面切割?
题目描述:
好像是给你几个k和b,y=kx+b啥的嘛,然后让你判断这几条线会把平面分成几部分。
这题我没有思路。也没时间了。
J (未解)怪物猎人?(名字肯定不叫这个)
题目描述:
太长了,记不清。
题解:
记不清了,只记得最后几分钟勉强写出了一个缺亿点细节,但是能过样例的答案。