蓝桥杯第20天(Python)(疯狂刷题第3天)
Posted Jin、焯
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯第20天(Python)(疯狂刷题第3天)相关的知识,希望对你有一定的参考价值。
题型:
1.思维题/杂题:数学公式,分析题意,找规律
2.BFS/DFS:广搜(递归实现),深搜(deque实现)
3.简单数论:模,素数(只需要判断到 int(sqrt(n))+1),gcd,lcm,快速幂(位运算移位操作),大数分解(分解为质数的乘积)
4.简单图论:最短路(一对多(Dijstra,临接表,矩阵实现),多对多(Floyd,矩阵实现)),最小生成树(并查集实现)
5.简单字符串处理:最好转为列表操作
6.DP:线性DP,最长公共子序列,0/1背包问题,最长连续字符串,最大递增子串
7.基本算法:二分,贪心,组合,排列,前缀和,差分
8.基本数据结构:队列,集合,字典,字符串,列表,栈,树
9.常用模块:math,datetime,sys中的设置最大递归深度(sys.setrecursionlimit(3000000)),collections.deque(队列),itertools.combinations(list,n)(组合),itertools.permutations(list,n)(排列) heapq(小顶堆)
目录
刷题
1.阶乘约数 (大数分解,循环)
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
#写法一
save=[0]*101 # 大数分解
for i in range(1,101):
for j in range(2,int(math.sqrt(i))+1): # 质数从2开始
while i%j==0: # 质数分解
save[j]+=1
i=i//j
if i>1: # 剩下的数是一个质数或者本身就是一个质数 例如10=2*5 17=1*17
save[i]+=1
ans=1
for i in save:
ans*=(i+1)
print(ans)
# 写法二
##MAXN = 110
##cnt = [0] * MAXN #记录对应质数幂次
##
##for i in range(1, 101):
## x = i
## # 质因子分解
## j = 2
## while j * j <= x:
## if x % j == 0: # 是一个质数约数
## while x % j == 0: #类似埃式筛
## x //= j
## cnt[j] += 1
## j += 1
## if x > 1:
## cnt[x] += 1
##
##ans = 1
##for i in range(1, 101):
## if cnt[i] != 0:
## ans *= (cnt[i] + 1) # 0 也是一种选择
##
##print(ans)
两种实现方法,因为是100!,所以需要遍历1-100进行大数分解,注意质数是从2开始的,1不是质数,只需要遍历2 - int( sqrt(n) )区间是否有n的因子,python取不到后面一位所以要加1,没得说明他是质数,同时如果分解后大于1说明没有被分解完,剩下的为质数,例如10,不是质数会变为1,例如4,9
2.质因子个数 (大数分解,质数,约数)
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
#对一个数进行大数分解
ans=0
n=int(input())
for i in range(2,int(math.sqrt(n))+1):
if n%i==0: #发现质数
ans+=1
#print(i) # 打印质数约数
while n%i==0: # 消除这个质数
n=n//i
if n>1:
#print(n) # 打印质数约数
ans+=1
print(ans)
送分题,会了第一题这道题就是秒出答案,只需要分解这一个数就行了,只需要求有多少个质数,注意判断分解后如果剩下的数大于1,说明还剩下了一个质数,答案需要加1.
3.等差数列(gcd函数用法)
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
# gcd(0,a)=a
n=int(input())
A=list(map(int,input().split()))
d=0
for i in range(len(A)-1):
d=math.gcd(d,A[i+1]-A[i])
#print(d) #打印d
# 需要处理d==0的情况
if d==0:
print(n)
else:
ans=(max(A)-min(A))//d+1
print(ans)
送分题,但是需要仔细判断情况,之前一直漏掉了d==0时的情况,没有考虑周全,出现÷0错误,需要注意gcd(0,a)= a,当不确定长度,边界范围的时候自己举例来确定。
4.快速幂(Fast_pow,位运算,移位操作)
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
b,p,q = map(int,input().split())
ans=1
while p: # 8次方 转为二进制 1000
if p&1: #当前位有1
ans=ans%q * b
b=b*b%q
p=p>>1 # 右移即/2
print(ans%q)
算是送分题,需要掌握位运算,左移乘2右移除2,使用while语句循环的时候注意在最后要改值,例如左加右减,右移左移,防止死循环。
5.最大最小公倍数(贪心,枚举讨论)
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
n=int(input())
# 第一时间想到 n*(n-1)*(n-2)
# 当n为奇数 最大值 n*(n-1)*(n-2)
# 当n为偶数 n和n-2可以约分
# n*(n-1)*(n-3) (不能被3整除)
# (n-1)*(n-2)*(n-3) (能被3整除)
if n%2==1:
print(n*(n-1)*(n-2))
else:
if n%3==0: #能被3整除
print((n-1)*(n-2)*(n-3))
else:
print(n*(n-1)*(n-3))
枚举所有情况,首先按照贪心想法取3个最大值,然后在讨论特殊情况,例如有约数这些,要找互质的。因为求最小公倍数最大值。
6.分解质因数(大数分解,字符串处理函数)
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
a,b=map(int,input().split())
for i in range(a,b+1):
save=i
ans=[] # 保存分解的数
for j in range(2,int(math.sqrt(i))+1):
if i%j==0:
while i%j==0:
ans.append(str(j))
i=i//j
if i >1: # 剩下的质数或者本身是质数没有分解,例如15,5,7
ans.append(str(i))
print(str(save)+'='+'*'.join(ans)) # " ".join(list) list里面的元素需要为字符类型
遍历这些数,对每一个数进行大数分解,难点在于知道分解后如果n值>1,说明分解后剩下了一个质数或者本身是质数不能分解为其他质数,然后就是字符串拼接操作,join()函数需要连接元素为字符串的才可以。
7.裁纸刀(思维题,内置函数的使用)
没什么难点,属于送分,需要读懂题意,就只有两种分法,使用内置函数min()取最小值就可以了,送分!!
8.蛇形填数(思维,观察规律)
求的是对角线上元素,观察对角线上元素的规律,即 +4 +8 +12 ,发现规律了直接套一个循环就可以了。
9.最大降雨量(思维题)
34 ---------> 49-15=34,上面手误了
思维题,注意重点,即两个中位数,不确定的时候举例,举特例来证明结论。
10.排序(字典序)
理解字典序的含义,即 'a'>'b',' a' > 'ab','ab'>'b'。这道题要求最短同时按照字典序,所以固定了答案,同时需要了解全排列,即 N*(N-1)/2 ,即 bca 排列成abc全排列 3*2/2=3
11.聪明的猴子(最小生成树,并查集)
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
def find(x):
if x==f[x]:
return f[x]
else:
f[x]=find(f[x])
return f[x]
def merge(x,y):
if find(x)!=find(y): # 需要合根,默认合向y
f[find(x)]=find(y) # x的根指向y的根
m=int(input()) # 猴子树
leng=list(map(int,input().split())) # 存储跳跃距离
n=int(input()) # 边数
dis = [0] # 存储坐标
for i in range(n):
dis.append(list(map(int,input().split())))
edge=[] #存储边
for i in range(1,n+1):
for j in range(i+1,n+1):
w=math.sqrt((dis[i][0]-dis[j][0])**2+(dis[i][1]-dis[j][1])**2) #计算距离
edge.append((i,j,w)) # 添加边,总共添加n*(n-1)/2条边
edge.sort(key=lambda x:x[2]) # 边从小到大排序
Max=0
num=0 # 当前处理了多少条边
f=[ i for i in range(n+1)]
for i in edge:
if find(i[0]) !=find(i[1]): # 最小生成树算法处理
merge(i[0],i[1])
Max=max(Max,i[2]) #在遍历过程中记录下最长边
num+=1
if num==(n-1): # 已经构建好了最小生成树
break
ans=0 # 记录能跳的猴子数量
for i in leng:
if i>=Max:
ans+=1
print(ans)
熟悉并查集的使用,最小生成树的构建方法,学会通过并查集,使用Kruskal Algorithm算法,即边从大到小排序,依次遍历最短边来构建最小生成树的方法来构建最小生成树。
12.路径(floyd或者dijstra实现)
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
# 初始化边
dp=[[2**100]*2030 for i in range(2030)]
def lcm(a,b):
return a//math.gcd(a,b)*b
# 赋初值
for i in range(1,2022):
for j in range(i+1,i+22): # 取不到最后一位
if j>2021:
break
dp[i][j]=lcm(i,j)
# floyd 算距离
for k in range(1,2022):
for i in range(1,2):
for j in range(1,2022):
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])
print(dp[1][2021])
floyd算法求得是多对多,但是时间复杂度为3阶多项式复杂度,Dijstra复杂度低一些,求的是1到多,floyd算法可以转换为求1到多,多到多,多到1。本题难点在于floyd算法的掌握,同时需要注意,floyd是通过矩阵实现的。
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
# Dijstr实现
def lcm(a,b):
return a//math.gcd(a,b)*b
def dij(s):
done=[0]*2022 # 标记是否处理过
hp=[]
dis[s]=0 # 自身到自身的距离为0
heapq.heappush(hp,(0,s)) # 入堆
while heapq:
u=heapq.heappop(hp)[1] # 出堆元素结点,边最小
if done[u]==0: # 没有被处理过
done[u]=1
#for i in dp[u]: # 遍历u的邻居 i:(v,w)
for i in range(len(dp[u])): # 遍历u的邻居 i:(v,w)
v,w=dp[u][i]
if done[v]==0: # 没有被处理过
dis[v]=min(dis[v],dis[u]+w)
heapq.heappush(hp,(dis[v],v))
dp=[[] for i in range(2022)] # 邻接表
dis=[2**100] * 2022 # 初始
# 邻接表更新
for i in range(1,2022):
for j in range(i+1,i+22):
if j>2021:
break
dp[i].append((j,lcm(i,j))) # 邻居和边长
s=1 # 开始起点
dij(s)
print(dis[2021])
13.出差(最短路径,矩阵实现Dijstra算法)
import sys #设置递归深度
import collections #队列
import itertools # 排列组合
import heapq #小顶堆
import math
sys.setrecursionlimit(300000)
def dij():
dist[1]=0 #很重要
for _ in range(n-1): # 还有n-1个点没有遍历
t=-1
for j in range(1,n+1):
if st[j]==0 and (t==-1 or dist[t]>dist[j]): #找到没处理过得最小距离点
t=j
for j in range(1,n+1):
dist[j]=min(dist[j],dist[t]+gra[t][j]) # t-j的距离,找最小值
st[t]=1 # 标记处理过
return dist[n]
n,m=map(int,input().split())
#下标全部转为从1开始
stay=[0]+list(map(int,input().split()))
stay[n]=0
gra = [[float('inf')] * (n+1) for _ in range(n+1)]
dist = [float('inf')] * (n+1)
st=[0]*(n+1) # 标志是否处理
for i in range(m):
u,v,w=map(int,input().split()) #这里重构图
gra[u][v]=stay[v]+w
gra[v][u]=stay[u]+w
print(dij())
本题难点在于重新搭建图,即将在每个城市滞留的时间更新到图里面。同时,DIjstra算法也很重要。
模板:(邻接表)
通过heapq实现,临接表存储(v,w),使用小顶堆存储,每次出堆得到初始距离最小距离的顶点,然后判断他的临接点是否被处理过,没有就更新这些临接点的距离,然后将计算后的距离入堆,要有标记矩阵,距离矩阵,邻接表
模板:(矩阵)
通过矩阵实现存储边信息,进行n-1次循环处理剩下的点,寻找没处理过得距离初始点最短的点,然后通过他更新其他点离初始点距离值,找到最小值。需要标记矩阵,距离矩阵,,矩阵存储边。
Bellman-ford算法
n,m=map(int,input().split())
t=[0]+list(map(int,input().split()))
e=[] #简单的数组存边
for i in range(1,m+1):
a,b,c = map(int,input().split())
e.append([a,b,c]) # 双向边
e.append([b,a,c])
dist=[2**50]*(n+1)
dist[1]=0
for k in range(1,n+1): # 遍历每个点,n个点,执行n轮问路
for a,b,c in e: # 检查每条边,每一轮问路,检查所有边
res=t[b]
if b==n:
res=0
dist[b]=min(dist[b],dist[a]+c+res) # 更新路径长度
print(dist[n])
14.蓝桥王国(Dijstra算法模板题)
import heapq # 导入堆
def dij(s):
done=[0 for i in range(n+1)] # 记录是否处理过
hp=[] #堆
dis[s]=0
heapq.heappush(hp,(0,s)) #入堆,小顶堆
while hp:
u=heapq.heappop(hp)[1] #出堆元素结点
if done[u]: #当前结点处理过
continue
done[u]=1
for i in range(len(G[u])): #遍历当前结点的邻居
v,w =G[u][i]
if done[v]:continue
dis[v]=min(dis[v],dis[u]+w) # 更新当前结点邻居的最短路径
heapq.heappush(hp,(dis[v],v))
n,m = map(int,input().split())#
s=1 # 从1开始访问
G=[[]for i in range(n+1)] #邻接表存储
inf = 2**50
dis = [inf]*(n+1) #存储距离
for i in range(m):# 存边,这里是单向边
u,v,w = map(int,input().split())
G[u].append((v,w)) #记录结点u的邻居和边长
dij(s)
for i in range(1,n+1):
if dis[i]==inf:
print("-1",end=' ')
else:
print(dis[i],end=' ')
模板题,需要熟练掌握和牢记,这是通过heapq小顶堆实现的,掌握模板就可以了
15.蓝桥公园 (Floyd算法模板题)
import os
import sys
# 请在此输入您的代码
#floyd算法,多对多
def floyd():
global dp
for i in range(1,n+1):
for j in range(1,n+1):
for k in range(1,n+1):
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])
n,m,q = map(int,input().split())
inf=2**120
dp=[[inf]*(n+1) for i in range(n+1)]
choice=[]
for i in range(m):
u,v,w=map(int,input().split())
dp[u][v]=w
dp[v][u]=w
for i in range(q):
s,d = map(int,input().split())
choice.append((s,d))
floyd()
for s,d in choice:
if dp[s][d]!=inf:
print(dp[s][d])
continue
print(-1)
Floyd算法模板题,熟练掌握就可以了,floyd用于多对多!
蓝桥杯备赛刷题
第十三届蓝桥杯第二场模拟赛题解
马上到蓝桥杯了,虽然省赛简单化,但是刷题是不可或缺的,下面我会更新蓝桥杯刷题题解,一起冲进国赛
文章目录
前言
马上到蓝桥杯了,虽然省赛简单化,但是刷题是不可或缺的,下面我会更新蓝桥杯刷题题解,一起冲进国赛
提示:以下是本篇文章正文内容,下面案例可供参考
填空题
第一题
0-255 所以最大为255
第二题
直接利用gcd求解最大公约数即可
import gmpy2
count=0
for i in range(2,2022):
if(gmpy2.gcd(2021,i)!=1):
count+=1
print(count)
答案:89
第三题
暴力解法求解, i=jj-kk
进而得出 i=(j-k)*(j+k)所以j-k一定是大于0的 所以j>k
i=( 一个正数)*j+k
所以j一定小于i的,所以遍历即可
count=0
flag=0
for i in range(2022):
flag=0
for j in range(2022):
if(flag==1):
break
for k in range(j):
if(flag==0):
if(i==j*j-k*k):
count+=1
flag=1
break
else:
continue
print(count)
答案是
1516
第四题
问题描述
小蓝要用01串来表达一段文字,这段文字包含 a, b, c, d, e, f 共 6 个字母,每个字母出现的次数依次为:a 出现 10次,b 出现 20 次,c 出现 3 次,d 出现 4 次,e 出现 18 次,f 出现 50 次。
小蓝准备分别对每个字母使用确定的01串来表示,不同字母的01串长度可以不相同。
在表示文字时,将每个字母对应的01串直接连接起来组成最终的01串。为了能够正常还原出文字,小蓝的编码必须是前缀码,即任何一个字符对应的01串都不能是另一个字符对应的01串的前缀。
例如,以下是一个有效的编码:a: 000
b: 111
c: 01
d: 001
e: 110
f: 100
其中 c 的长度为 2,其它字母的编码长度为
3,这种方式表示这段文字需要的总长度为:103+203+32+43+183+503=312。上面的编码显然不是最优的,将上面的 f
的编码改为 10,仍然满足条件,但是总长度为 262,要短
50。要想编码后的总长度尽量小,应当让出现次数多的字符对应的编码短,出现次数少的字符对应的编码长。请问,在最优情况下,编码后的总长度最少是多少?
代码如下(示例):
一看就是哈夫曼编码,这里由于是填空题,直接手算就行了,多的距离近,少的距离远
计算如下
50*1+2*20*3*18+10*4*4+4*3
数据结构哈夫曼知识了
画个图手算一下就有了
第五题
下面的矩阵中包含 ABCDEF 六种字符,请问出现最多的字符出现了几次?
FFEEFEAAECFFBDBFBCDA
DACDEEDCCFFAFADEFBBA
FDCDDCDBFEFCEDDBFDBE
EFCAAEECEECDCDECADDC
DFAEACECFEADCBFECADF
DFBAAADCFAFFCEADFDDA
EAFAFFDEFECEDEEEDFBD
BFDDFFBCFACECEDCAFAF
EFAFCDBDCCBCCEADADAE
BAFBACACBFCBABFDAFBE
FCFDCFBCEDCEAFBCDBDD
BDEFCAAAACCFFCBBAAEE
CFEFCFDEEDCACDACECFF
BAAAFACDBFFAEFFCCCDB
FADDDBEBCBEEDDECFAFF
CDEAFBCBBCBAEDFDBEBB
BBABBFDECBCEFAABCBCF
FBDBACCFFABEAEBEACBB
DCBCCFADDCACFDEDECCC
BFAFCBFECAACAFBCFBAF
data = pd.read_csv(
‘https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv’)
print(data.head())
利用collect来进行统计
```python
from collections import Counter
s='FFEEFEAAECFFBDBFBCDADACDEEDCCFFAFADEFBBAFDCDDCDBFEFCEDDBFDBEEFCAAEECEECDCDECADDCDFAEACECFEADCBFECADFDFBAAADCFAFFCEADFDDAEAFAFFDEFECEDEEEDFBDBFDDFFBCFACECEDCAFAFEFAFCDBDCCBCCEADADAEBAFBACACBFCBABFDAFBEFCFDCFBCEDCEAFBCDBDDBDEFCAAAACCFFCBBAAEECFEFCFDEEDCACDACECFFBAAAFACDBFFAEFFCCCDBFADDDBEBCBEEDDECFAFFCDEAFBCBBCBAEDFDBEBBBBABBFDECBCEFAABCBCFFBDBACCFFABEAEBEACBBDCBCCFADDCACFDEDECCCBFAFCBFECAACAFBCFBAF'
s=Counter(s)
s1=dict(s)
print(s1.values())
答案是78
第六题
问题描述
小蓝要到店里买铅笔。铅笔必须一整盒一整盒买,一整盒 12 支,价格 p 元。小蓝至少要买 t 支铅笔,请问他最少花多少钱?
输入格式
输入一行包含两个整数 p、t,用一个空格分隔。
输出格式
输出一行包含一个整数,表示答案。
样例输入
5 30
样例输出
15
样例说明
小蓝至少要买3盒才能保证买到30支铅笔,总共花费 15 元。
评测用例规模与约定
对于所有评测用例,1 <= p <= 100,1 <= t <= 10000
除数问题
list1= input('输入一行包含两个整数 p、t,用一个空格分隔').split(' ')
a=int(list1[0])
b=int(list1[1])
if(b%12==0):
print(b//12*a)
else:
print((b//12+1)*a)
第七题
问题描述
给定一个三角形的三条边的长度 a, b, c,请问这个三角形是不是一个直角三角形。
输入格式
输入一行包含三个整数 a, b, c,表示三角形三边的长度,相邻整数之间用一个空格分隔。
输出格式
如果是直角三角形,输出“YES”(全大写),否则输出“NO”(全大写)。
样例输入
3 4 5
样例输出
YES
样例输入
4 5 4
样例输出
NO
评测用例规模与约定
对于所有评测用例,1 <= a, b, c <= 1000。
一共三种情况:
a*a+b*b==c*c
a*a+c*c==b*b
a*a==c*c+b*b
```python
list1=input('输入一行包含三个整数 a, b, c,表示三角形三边的长').split(' ')
a=int(list1[0])
b=int(list1[1])
c=int(list1[2])
if(a*a+b*b==c*c or a*a+c*c==b*b or a*a==c*c+b*b):
print('YES')
else:
print("NO")
加个条件过去就行了
第八题
问题描述
n 个小朋友正在做一个游戏,每个人要分享一个自己的小秘密。 每个小朋友都有一个 1 到 n 的编号,编号不重复。
为了让这个游戏更有趣,老师给每个小朋友发了一张卡片,上面有一个 1 到 n 的数字,每个数字正好出现一次。
每个小朋友都将自己的秘密写在纸上,然后根据老师发的卡片上的数字将秘密传递给对应编号的小朋友。如果老师发给自己的数字正好是自己的编号,这个秘密就留在自己手里。
小朋友们拿到其他人的秘密后会记下这个秘密,老师会再指挥所有小朋友将手中的秘密继续传递,仍然根据老师发的卡片上的数字将秘密传递给对应编号的小朋友。
这样不断重复 n 次。 现在,每个小朋友都记下了很多个秘密。
老师现在想找一些小朋友,能说出所有秘密,请问老师最少要找几个小朋友?输入格式
输入的第一行包含一个整数 n。 第二行包含 n 个整数 a[1], a[2], …,
a[n],相邻的整数间用空格分隔,分别表示编号 1 到 n 的小朋友收到的数字。输出格式
输出一行包含一个整数,表示答案。
样例输入
6 2 1 3 5 6 4
样例输出
3
样例说明
最终小朋友 1, 2 互相知道了对方的秘密,小朋友 3 只知道自己的秘密,小朋友 4, 5, 6 互相知道了对方的秘密。 至少要找
3 个小朋友才能说出所有秘密。评测用例规模与约定
对于 30% 的评测用例,2 <= n <= 30。 对于 60% 的评测用例,2 <= n <= 1000。
对于所有评测用例,2 <= n <= 100000。
————————————————
我们这里利用填坑思想,如果 遍历过程就是遍历signal数组的过程,并将其填1 如果已经是1了那末就+1,因为要想知道对方秘密,那末一定是能按照标志能便利所有了,如果中断了那末就将结果+1
n=5
temp=[]
count=0
s='2 3 1 5 4'.split(' ')
print(s)
sigal=n*[0]
p=int(s[0])-1
ee=0
while 1:
if(sigal[p]!=1):
sigal[p]=1
p=int(s[p])-1
ee+=1
if(ee==n):
break
else:
p = int(s[ee])-1
print(sigal)
count+=1
print(count+1)
最后一次没有循环,所以结果再加一就行了
以上是关于蓝桥杯第20天(Python)(疯狂刷题第3天)的主要内容,如果未能解决你的问题,请参考以下文章