2024蓝桥杯 Python A组题目分析与讲解
文章目录
- D.回文数组
- F.砍柴
D.回文数组
D.回文数组
- 首先看这个测试用例的范围,要求我们要使用
o(n)
的时间复杂度的算法进行求解,相差的问题?那么我们肯定是要看一下对应的位置的这个数字的差值!!!
,这是一个很自然的解法,大家要多一点积累 - 所以我们要得到一个数组,该数组记录了
原始的数组对应的回文位置的数字的差值,这个数组的长度是 n //2,奇数的长度的数组不用考虑中间的那个元素
- 接着,问题就转化为
将差值数组变为全0数组所需的最少的操作次数
,那么我们首先应该想到这个贪心+枚举
的思路 - 贪心:
尽可能使用对两个元素操作,迫不得已才可以使用一个元素的操作
,那么什么时候可以使用这个两个元素的操作?那当然是,当前元素与后面的那一个元素的符号相同,那么我们就可以同时加或者减去它们的较小值的绝对值 - 总体的问题的情况如下:
cha[i]*cha[i+1]>0:
也就是同号,可以使用两个对象的操作,操作完成之后会转化为下面的两个情况的其中一种情况cha[i]==0
:此时直接continue
,不用操作cha[i]*cha[i+1]<0
:不同号,只能单独对这个cha[i]
自己操作
n = int(input())
a = list(map(int,input().split()))
cha = [0]*(n//2)
# 得到相差的数组
for i in range(n//2):
cha[i] = a[i] - a[n-1-i]
# 开始贪心枚举
ans = 0
# 由于要判断后一个的情况,所以最后一个要单独判断
for i in range(n//2-1):
if cha[i] == 0:
continue
# 同号的问题
if cha[i]*cha[i+1] > 0:
change = min(abs(cha[i]),abs(cha[i+1]))
ans += change
# 如果是正数
if cha[i] > 0:
cha[i],cha[i+1] = cha[i]-change,cha[i+1]-change
# 如果是负数
else:
cha[i],cha[i+1] = cha[i]+change,cha[i+1]+change
# 如果两个对象的操作没使得当前cha[i]==0,或者是情况3,也就是cha[i]与cha[i+1不同号
if cha[i] == 0:
continue
else:
ans += abs(cha[i])
ans += abs(cha[-1])
print(ans)
F.砍柴
F.砍柴
- 对于这个最优策略的问题:
- 首先,每次的选择都是选择一个质数,所以你得首先先把最大范围内的质数全部筛选出来,在这里我们使用
欧拉筛
进行筛选 - 对于最优策略的问题,首先考虑可以使用一个
dp
数组来记录对应的n
所对应的情况下,小蓝能否获胜,对于当前的n,如果在找到一个dp[n-p]=0,则说明小蓝是可以获胜的,否则就不行
美中不足的是,这个代码的时间复杂度过高,只能通过
10/20
的测试用例,对于最后的dp数组的求解,如果改为10**5+1,则代码会运行很久
# 总体来说,就是不断的遍历吧
# 首先求解出全部的质数,对于当前的选择,枚举这个<=x的质数,通过这个记忆化很快可以知道
dp = [0]*(10**5+1)
dp[2],dp[3] = 1,1
zhistore = set()
iszhi = [True]*(10**5+1)
iszhi[0],iszhi[1] = False,False
# 使用质数筛,得到 10**5范围内全部的质数
for i in range(2,10**5+1):
if iszhi[i]:
zhistore.add(i)
for j in zhistore:
if i * j > 10**5:
break
iszhi[i*j] = False
# 全部的质数都存储在这个iszhi中
isprime = [i for i,c in enumerate(iszhi) if c == True]
for i in range(4,10**4+1):
# 小蓝所做出的选择j
flag = 0
if iszhi[i]:
dp[i] = 1
continue
for j in isprime:
if j>i:
break
if dp[i-j] == 0:
# 表示找到了
flag = 1
dp[i] = 1
break
T = int(input())
for _ in range(T):
n = int(input())
print(dp[n])
- 后面经过检查,发现还是这个动态规划存在问题,原本的代码使用的是对于当前的
i
,查询是否存在减去质数的dp[]是必败的状态
,这样的话,效率会十分慢,正确的做法应该是找到必败的状态dp[i] == 0,然后遍历质数,当前的必败状态i+p的时候对于小蓝来说就是必赢的状态
# 总体来说,就是不断的遍历吧
# 首先求解出全部的质数,对于当前的选择,枚举这个<=x的质数,通过这个记忆化很快可以知道
dp = [0]*(10**5+1)
dp[2],dp[3] = 1,1
zhistore = []
iszhi = [True]*(10**5+1)
iszhi[0],iszhi[1] = False,False
# 使用质数筛,得到 10**5范围内全部的质数
for i in range(2,10**5+1):
if iszhi[i]:
zhistore.append(i)
for j in zhistore:
if i * j > 10**5:
break
iszhi[i*j] = False
if i % j == 0:
break
# 全部的质数都存储在这个iszhi中
isprime = [i for i,c in enumerate(iszhi) if c == True]
for i in range(4,10**5+1):
if dp[i] == 0:
for j in isprime:
if i + j < 10**5:
dp[j] = 1
T = int(input())
for _ in range(T):
n = int(input())
print(dp[n])
作者:JNU freshman