2021年软件类第十二届蓝桥杯第二场省赛 python组 F-J题解
Posted 风信子的猫Redamancy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021年软件类第十二届蓝桥杯第二场省赛 python组 F-J题解相关的知识,希望对你有一定的参考价值。
2021年软件类第十二届蓝桥杯第二场省赛 python组 F-J题解
文章目录
试题 F:小平方
【样例输入】
5
【样例输出】
2
思路
这道题也很简单,实际上就一个枚举就可以
简单来说,就是有手就行哈哈,第一题可能让我兴奋一下,等等就难受了
代码
'''
比较简单就是枚举即可
'''
cnt = 0
n = int(input())
for i in range(1,n):
if (i*i)%n <= n/2:
cnt += 1
print(cnt)
试题 G:完全平方数
【样例输入】
12
【样例输出】
3
思路
这道题的话,前面就在思考,穷举的办法行不行的通,但是后面想了想,行不通的,因为我们的最大数据有10的12次方,所以说我们需要一个更好的算法
想着想着,我突然灵机一动,我们其实可以利用一种分解质因数的思路去求解,比如说我们的样例输入中有一个12,这个12我们可以进行分解质因数,也就是12=2x2x3,我们会发现,我们只要乘上一个3,就是我们完全平方数了,也就是2x2x3x3,这样我们的数据两两配对就是平方数,所以我们的x最后就是3。
所以思路就出来了,我们需要对我们的数据进行一个分解质因数,如果我们当前质因数的个数为奇数的话,我们就需要多乘一个,所以x就乘上这个质因数,这样就可以完成配对。
对于质数来说,本身无法分解质因数,或者说,分解的质因数就是他本身,所以我们就可以直接输出本身就可以的了
代码
'''
利用一种分解质因数的方法来计算
'''
from collections import Counter
h = Counter() # 计数,质因数的个数
n = int(input())
for i in range(2,int(n**0.5)+1): # 循环遍历
while n%i==0: # 进行分解质因数
n = n//i
h[i] += 1 # 计算质因数个数
x = 1
for i in h:
if h[i]%2 == 1: # 如果质因数的个数为奇数,就乘x
x = x*i
if x == 1:
print(n) # 本身是一个质数,不用分解,打印自身
else:
print(x) # 得到分解质因数后的值
我们也可以将代码简化一下,其实就是
n = int(input())
x = 1
for i in range(2,int(n**0.5)+1): # 循环遍历
cnt = 0
while n%i==0: # 进行分解质因数
n = n//i
cnt += 1
if cnt & 1:
x *= i
print(n*x)
题目 H:负载均衡
【样例输入】
2 6
5 5
1 1 5 3
2 2 2 6
3 1 2 3
4 1 6 1
5 1 3 3
6 1 3 4
【样例输出】
2
-1
-1
1
-1
0
思路
这道题的话,我采用了优先队列的想法,似乎很多人是使用二重循环的,但是我觉得二重循环肯定是过不了的,因为在这一部分中数据量最大有10的9次方,最多就是10的18次方,很明显是不可能过的了的
这里就考虑了一个优先队列的思想,这里还用了二叉堆,当然也可以用queue库里面的PriorityQueue,也是优先队列,本质上这里面的优先队列也是用二叉堆实现的,所以我索性就用了二叉堆的想法。
具体呢,我觉得就是一个模拟的想法,首先我们分配一个一个电脑,如果发现电脑资源不够,就输出-1,如果发现电脑资源足够,就输出剩下的资源,不过难点就是,你怎么样记录我们的时间,因为有可能运行后面的任务的时候,前面的电脑的资源释放了,所以这时候我就用了优先队列的思想
我们可以将时间,机器,资源都放在一个元组中,然后会按时间进行排序,如果判断时间相同,就说明前面的任务释放资源了,这时候我们就把该机器的资源进行一个释放,再去对我们的任务来分配资源。这样模拟过程,就可以很容易完成我们的结果,而且速度也是很快的,我们只需要判断优先队列中的前几个是不是与当前时刻相同,一旦发现不相同的,后面的时间都是大于当前时刻的,就可以不用考虑。
不过后来我发现我考虑少了一个点,我们判断时间的时候不应该只是判断时间相等,而是一个小于等于的关系,因为可能在分配任务的时刻的中间,我们的资源就进行了释放了。
同时这里也给出一个优先队列和二叉堆的链接,Python 优先队列(priority queue)和堆(heap)
代码
import heapq
heap = []
n,m = map(int,input().split()) # 计算机数和任务数
v = list(map(int,input().split())) # 计算机的资源
v = [0] + v
for i in range(m):
# a为时刻,b为机器,c为耗费时间,d为算力资源
a,b,c,d = map(int,input().split())
# 判断优先队列是否存有资源
while heap:
x = heap[0]
if x[0] <= a: # 判断释放资源的时间 是否小于等于 当前时刻
v[x[1]] += x[2] # 释放资源
heapq.heappop(heap)
else:
break
# 判断是否有资源,如果有资源就分配,并加入优先队列
if v[b] >= d:
v[b] -= d
heapq.heappush(heap,(a+c,b,d))
print(v[b]) # 打印剩余算力
else:
print(-1)
试题 I:国际象棋
思路
这一道题呢,我们肯定知道,如果采用dfs是一定会超时的,所以这里采用的是一种状压dp的思想
因为我们的数据中的行是
n<=6
的,所以我们就可以利用状态压缩DP
对于马走日这个操作而言,前前行,前行状态均会影响到本行的状态。即首先前行的马不能与前前行冲突,其次,本行的马不能与前行、前前行冲突。那么这个本行的方案就是一种可行方案。
但是我们的马的数量也有限制,所以我们还需要一个维度来进行记录,也就是我们k
理论上来讲,枚举行、列都是可以的。
但是注意状压
dp
,我们一定是二进制枚举数量小的那一个维度,在此是n
,行比较小,故二进制枚举行,循环枚举列。f[i][a][b][j]
表示已经放好了i-1
列之前的马,且第i
列状态为b
,i-1
列的状态为a
,放置马的总数量为j
的方案数。
所以我们需要对我们的
a
和b
进行枚举,将前行、前前行所有满足放置个数为k
的状态进行累加,res += f[m][a][b][k]
。
【样例输入】
1 2 1
【样例输出】
2
【样例输入】
4 4 3
【样例输出】
276
【样例输入】
3 20 12
【样例输出】
914051446
代码
'''
主要思路就是利用状压dp来解决
如果直接用我们的dfs应该是必会超时的
因为我们的行数和列数和马的数不是一样的
'''
# 计算二进制中1的个数,也就是计算当前列增加了多少个棋子
def lowbit(x):
res = 0
while x:
# print(bin(x))
res += 1
x -= x&-x # 减去最低位的1
return res
n,m,k = map(int,input().split())
# f[i][a][b][t] i 代表前i列,a代表前列,b代表当前列的状态集合,t代表已经用过多少个棋子
# f[n][m][m][k]
f = [[[[0]*(k+1) for _ in range(1<<n)] for _ in range(1<<n)] for _ in range(m+1)]
f[0][0][0][0] = 1 # 初始化为1
MOD = int(1e9+7)
for i in range(1,m+1): # 循环枚举列,二进制枚举行的情况
for a in range(1<<n): # 前一列
for b in range(1<<n): # 当前列
if (b>>2) & a or (b<<2) & a: continue
for c in range(1<<n): # 前前列
if (c<<2) & a or (c>>2) & a: continue # 与上一列发生冲突
if (c<<1) & b or (c>>1) & b: continue # 与当前列发现冲突
t = lowbit(b) # 当前列放了 t 匹马
for j in range(t,k+1): # 状态转移,也就是背包计数
f[i][a][b][j] = (f[i][a][b][j] + f[i-1][c][a][j-t]) % MOD
# 放了m列,当前状态为b,上一个状态为a,总共放了k 匹马的方案数
res = 0
for a in range(1<<n):
for b in range(1<<n):
res = (res + f[m][a][b][k]) % MOD
print(res)
试题 J:完美序列
思路
这道题看我们的数据来说,还是特别大的,但是一下子让我来看的话,我就想到一种穷举的方法,对全排列的子序列进行一个枚举,如果发现,可以从小到大进行枚举,如果发现是完美子序列,就计算价值和,不过我知道,这种方法只能拿20分了,不过如果都做到这里了,拿20%的分折算就是5分了。
然后我在想,在我们计算子序列的时候,首先我们知道,对于全排列来说,我们的子序列是会有重复的,比如(3,2,1)和(2,1,3)都有子序列(2,1),这一部分如果重复枚举的话就容易造成超时
所以我觉得正确的做法是,对于合适的子序列,我们是要看在全排列中占的比例大概有多少,然后,就是互相找因数,然后判断进行计算。
不过我觉得J题现在纠结没什么意思,还是先看看其他题,准备考试了,加油
代码
# 持续更新 暂时先复习
试题的pdf在网盘里,可以自取
链接:https://pan.baidu.com/s/17qliVu31SCGtXCQVEfldZA
提取码:6666
以上是关于2021年软件类第十二届蓝桥杯第二场省赛 python组 F-J题解的主要内容,如果未能解决你的问题,请参考以下文章
2021年软件类第十二届蓝桥杯 省赛 python组 A-E题解
2021年软件类第十二届蓝桥杯 省赛 python组 F-J题解
2021 第十二届蓝桥杯大赛软件赛省赛(第二场),C/C++大学B组题解
2021 第十二届蓝桥杯大赛软件赛省赛(第二场),C/C++大学B组题解