蓝桥杯2022Python组
1.排列字母
用一个sorted就好了,没啥好说的
s = 'WHERETHEREISAWILLTHEREISAWAY'
s = sorted(s) # 变成列表形式了
print(''.join(s))
2.寻找整数
这题我刚开始以为答案只能是11和17的倍数,就在他们的倍数里面找,发现不对,他还有可能是50以上的质数的倍数。但是他肯定是11和17的倍数是没跑的,就是187的倍数,肯定不可能是187的偶数倍,因为mod2余1,所以我们从187开始搜,跨度为187*2,但是那样也很多,我们给他加一点条件看看能不能找到什么规律。
我是加了最多五个,作为条件,找到了规律他们是一个等差数列,因此我们就可以拿那个等差数列去寻找我们最终想要的
# a = 0
# res = []
# for i in range(187,10**17,374): # 不能被我除尽,一定不是187的偶数倍
# if i % 49 == 46 and i % 48 == 41 and i % 47 == 5 and i % 46 == 15 and i % 45 == 29:
# a = a+1
# res.append(i)
# if a == 5:break
# print(res)
mod = [(2, 1), (3, 2), (4, 1), (5, 4), (6, 5), (7, 4), (8, 1), (9, 2), (10, 9),
(11, 0), (12, 5), (13, 10), (14, 11), (15, 14), (16, 9), (17, 0), (18, 11), (19, 18),
(20, 9), (21, 11), (22, 11), (23, 15), (24, 17), (25, 9), (26, 23), (27, 20), (28, 25), (29, 16),
(30, 29), (31, 27), (32, 25), (33, 11), (34, 17), (35, 4), (36, 29), (37, 22), (38, 37), (39, 23),
(40, 9), (41, 1), (42, 11), (43, 11), (44, 33), (45, 29), (46, 15), (47, 5), (48, 41),(49,46)
]
for i in range(5458460249,10**17,12590206409 - 5458460249):
for a,b in mod:
if i % a != b:break
else:print(i)
3.纸张尺寸
这题又变得简单了,一题难一题简单的,简单的枚举一下就好了
a = 1189
b = 841
res = []
for i in range(10):
res.append([a,b])
if a > b: a = a//2
else: b = b // 2
n = input()
if n == 'A0':
print(res[0][0])
print(res[0][1])
if n == 'A1':
print(res[1][1])
print(res[1][0])
if n == 'A2':
print(res[2][0])
print(res[2][1])
if n == 'A3':
print(res[3][1])
print(res[3][0])
if n == 'A4':
print(res[4][0])
print(res[4][1])
if n == 'A5':
print(res[5][1])
print(res[5][0])
if n == 'A6':
print(res[6][0])
print(res[6][1])
if n == 'A7':
print(res[7][1])
print(res[7][0])
if n == 'A8':
print(res[8][0])
print(res[8][1])
if n == 'A9':
print(res[9][1])
print(res[9][0])
4.位数排序
最开始的想法就是创建一个字典,每个数都对应这他自己的位数和,然后让位数和去排序,是可行的
n,m = int(input()),int(input())
dic = {}
for i in range(1,n+1):
dic.update({i:sum([int(x) for x in str(i)])})
res = sorted(dic.items(),key = lambda x:x[1])
print(res[m-1][0])
PS 因为他本身已经因为自己的数排序了,就是1,2,3,4所以位数和排完后不需要再去对他们自己进行排个序
5.蜂巢
能把坐标系画出来也不难了这题,很简单,你想想,比如往东偏北60°走两格,是不是y+2,x+1?那我们就这样想,往东偏北60*走一格是y+1,x+0.5 ,这样类似的就行了。然后我们坐标系就建好了。
建好之后找他们两的位置就不难,我们可以画图发现,如果abs(y1-y2) > abs(x1-x2),那我们的最短距离就是abs(y1-y2).可以画个图尝试一下,需要的话我可以再补。
如果abs(y1-y2) < abs(x1-x2)呢,我们还是先走y轴的部分,走完呢y轴斜着走肯定x也会变,走到一个点和另一个点平行,然后再走X轴直线就好了(当然画图会形象,有条件的可以去画画)
def find(x,y,n,step):
if n == 0:
x -= step
return x,y
if n == 1:
x -= 0.5*step
y += step
return x,y
if n == 2:
x += 0.5*step
y += step
return x,y
if n == 3:
x += step
return x,y
if n == 4:
x += 0.5*step
y -= step
return x,y
if n == 5:
x -= 0.5*step
y -= step
return x,y
if __name__ == '__main__':
d1,p1,q1,d2,p2,q2 = map(int,input().split())
xb1,yb1 = find(0,0,d1,p1)
xb,yb = find(xb1,yb1,(d1+2)%6,q1)
xc1,yc1 = find(0,0,d2,p2)
xc,yc = find(xc1,yc1,(d2+2)%6,q2)
if abs(yc - yb) >= abs(xc - xb): print(abs(yc-yb))
else: print(int(abs(yc - yb) + (abs(xc - xb) - 0.5*abs(yc - yb))))
6.消除游戏
很简单,我们遍历一遍,把边缘字符的坐标给加入到一个集合里,然后删除就好了。
def eliminate(s):
a = set()
for i in range(1,len(s)-1):
if s[i-1] == s[i] and s[i] != s[i + 1]:
a.add(i+1)
a.add(i)
if s[i] == s[i + 1] and s[i] != s[i - 1]:
a.add(i)
a.add(i-1)
s = list(s)
for i in a:
s[i] = '' # 边缘的都变成’‘
return ''.join(s)
if __name__ == '__main__':
s = input()
for _ in range(2**64):
temp = s
s = eliminate(s)
if temp == s:
print(s)
break
if len(s) == 0:
print('EMPTY')
break
7.全排列的价值
这个如果写多重循环肯定会TLE的哦,我们可以发现一个递推公式
参考与https://blog.csdn.net/BlacKingZ/article/details/124066488
当然大佬最后有一块递推的部分直接略过了,我这边补充一下,就是一层一层往下推就好了,记住P1 = 0 P2 = 1
8.技能升级
我感觉他这个题简单一会难一会的,这题也蛮简单的。。我还在想有没有什么坑呢,应该是没有,就直接遍历每次取最大就好了
if __name__ == '__main__':
n,m = map(int,input().split())
A = []
B = []
for i in range(n):
a,b = map(int,input().split())
A.append(a)
B.append(b)
res = 0
for _ in range(m): # O(mn)
maxa = max(A)
res += maxa
index1 = A.index(maxa)
A[index1] -= B[index1]
print(res)
PS : 也可以不用max和index ,用sorted 直接排序,但要知道sorted 在python 中的时间复杂度是O(nlogn),max和index都是O(n) ,所以我这样总复杂度是O(mn),你用sorted的话时间复杂度是O(mnlogn),会多个logn
9.最长不下降子序列
这题我一直没有一个很好的解法,最开始超级暴力就是一个个变,变完后去搜他这个序列的最长不下降子序列,发现时间复杂度达到了O(n^3logn),先给你们看看暴力的,应该最多只能多前30%
import copy
时间复杂度O(n^3logn) 太大了,能过1000就不错了
def isfdj(lst):
return lst == sorted(lst)
if __name__ == '__main__':
n,k = map(int,input().split())
ls = [int(x) for x in input().split()]
l = []
for i in range(0,n-k): #O(n)
if i == 0:
tmp = copy.deepcopy(ls)
for j in range(k): #O(k)
tmp[j] = 0
else:
tmp = copy.deepcopy(ls)
t = ls[i-1]
for j in range(i,i+k):
tmp[j] = t
ll = 0
low = 0
high = 0
while high < n: #O(n)
if isfdj(ls[low,high]): # O(nlogn)
ll += 1
else:
l.append(ll)
ll = 0
low = high
high += 1
l.append(ll)
print(len(l))
就是每个地方都根据k变,然后遍历变完之后的序列。不对。。。这个是最长连续不下降序列。。我搞错了,那我们直接看另一种吧,时间复杂度被我降到了O(O^2logn)虽然还是很大,但我能力就到这了
import copy
时间复杂度O(n^3logn) 太大了,能过1000就不错了
def isfdj(lst):
return lst == sorted(lst)
def erfen(a,k): # 找到单调递增序列a中 第一个比k大的元素
l = 0
r = n
while l < r:
mid = (l+r)//2
if a[mid] > k:r = mid
else : l = mid
if r - l == 1:return r
return 0
if __name__ == '__main__':
n,k = map(int,input().split())
ls = [int(x) for x in input().split()]
l = []
for i in range(0,n-k): #O(n)
if i == 0:
tmp = copy.deepcopy(ls)
for j in range(k): #O(k)
tmp[j] = 0
else:
tmp = copy.deepcopy(ls)
t = ls[i-1]
for j in range(i,i+k):
tmp[j] = t
res = []
d =[0]*(n+1)
d[1] = tmp[0]
len = 1
for i in range(1,n):
if tmp[i] >= d[len]:
len += 1
d[len] = tmp[i]
else: #换掉该换的
j = erfen(d,tmp[i])
d[j] = tmp[i]
res.append(len)
print(max(res))
最开始每个地方都根据K去变,就是把后面K个数变成最前面的一个数的前一个数的值,然后去找这个字符串的最长不下降子序列,用到了二分查找。
把最长不下降子序列放到一个d里面,d[len]表示这个子序列最大的一个数,如果后一个数大于d[len],那么len++,d[len] = 后一个数
如果后一个数小于d[len]呢?那我们就把他放到他该放的位置上去,并不是直接扔掉,他后面可能会有用的,可以代替d[len]使得最长不下降子序列的最大元素更小。那么我们现在就是要找到一个他的位置,是什么位置呢?在d中找到一个数,这个数是最先>他的,也就是在这个数之前的数都小于等于他,那么他把这个大于他的数给替换到,可以用到二分查找。总复杂度是O(nlogn)
10.最优清零方案
这题在我看来还是蛮简单的,我也不知道会不会TLE啊,我在蓝桥杯官网找不到这题没办法去测试。就是能消除连续K个肯定是消除连续K个对吧,那我们就从头开始遍历,把K个数当做一个滑动窗口,如果这个滑动窗口中有0,我们就往下滑一格(可以优化直接滑到什么位置,我这里没有做),没有0,我们就把这K个数全部减1,然后直到到最后。 剩下的只能一个个减去1了,就求个sum
if __name__ == '__main__':
n,k = map(int,input().split())
A = [int(x) for x in input().split()]
res = 0
for i in range(0, n - k+1):
while 0 not in A[i:i+k]:
for j in range(i,i+k):
A[j] -= 1
res += 1
res += sum(A)
print(res)