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 列状态为 bi-1 列的状态为 a,放置马的总数量为 j 的方案数。


所以我们需要对我们的ab进行枚举,将前行、前前行所有满足放置个数为 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组题解

2021.5.9 第十二届蓝桥杯大赛软件赛省赛第二场大学B组(个人题解)

《蓝桥杯真题》:2021单片机省赛第二场(第十二届第二场)暨第十三届蓝桥杯赛前模拟试题