python比赛2020_计蒜客2020 蓝桥杯大学 A 组模拟赛(三)Python题解

受限于版权,不再复制题面。题目可以通过购买计蒜客蓝桥杯2020课程,或者单独复现比赛获取。这里仅仅提供我的Python解答和代码。

总体来说比第一次模拟赛题目难度有下降,有参考性。

A.抛硬币

不用说了,独立事件,答案是0.50

B.求零点

经典的二分求解。当然你如果真的有耐心也可以暴力枚举(雾)。答案

def f(x):

return x**5-15*x**4+85*x**3-225*x**2+274*x-121

L=1.5

R=2.4

while L+1E-10

M=(L+R)/2

if f(M)>0:

L=M

else:

R=M

print("%.6f"%L)

C.棋盘放置

似乎有点像需要dfs搜索的问题。但是这个手动枚举更方便。很容易知道答案不会超过总对角线数15。同时可以构造出一种放置14个的方案(最左边一列放8个,最右边一列放6个),容易看出,不可能比14更加优了。

当然如果有多余时间,也可以用代码验证。

D.突破障碍

不错的一道题。属于迷宫类型,但是又有所不同。题目中要求S到T穿梭过的最小障碍物个数。考虑总的代价

,代表到达某个格子经过的障碍数(包括自身)。由于每走过一格

不一定增长1,因此单纯四方向扩展,队列不一定会非递减。似乎不能用广搜bfs直接求解。这里我们需要稍微改造广搜,不是简单地把相邻格子放入队列,而是将相邻格子所有连通的未访问的

格子都更新好

,并且放入队列。这是因为这些格点的

值已经确定和新格子一致,不会再出现有更小的答案了。这么做的话,队列中的状态在扩展过程中

就都是非递减的而且差值不过1。每一步更新的正确性有所保证。

实现中采用了一个

函数来扩展相邻

格子,包含一个广搜。因此总体上有点嵌套的感觉。

答案为6。如果时间紧张,可以先蒙上一个答案。

from queue import Queue

dx=(0,1,0,-1)

dy=(1,0,-1,0)

n=m=15

s=[]

for i in range(n):

s.append(input())

if s[i].__contains__("S"):

sta=(i,s[i].index("S"))

if s[i].__contains__("T"):

ed=(i,s[i].index("T"))

Q=Queue()

stp=[[-1]*m for i in range(n)]

def expand(x,Orig_Q):

Q=Queue()

Q.put(x)

Orig_Q.put(x)

while not Q.empty():

u=Q.get()

for j in range(4):

v=(u[0]+dx[j],u[1]+dy[j])

if 0<=v[0]

stp[v[0]][v[1]]=stp[u[0]][u[1]]

Q.put(v)

Orig_Q.put(v)

stp[sta[0]][sta[1]]=0

expand(sta,Q)

while not Q.empty():

u=Q.get()

for j in range(4):

v=(u[0]+dx[j],u[1]+dy[j])

if 0<=v[0]

stp[v[0]][v[1]]=stp[u[0]][u[1]]+1

expand(v,Q)

print(stp[ed[0]][ed[1]])

E.歌手

可以通过

搜索来求解,也可以通过枚举全排列来求解。因为只有9个数字,所以直接用permutations生成器来做。

答案为:

(注意permutations和C++中的next_permutation还是有所不同的,前者是不管你有重复数字的,[1,2,3,3]会被枚举两遍)

from itertools import permutations

a=[1,1,1,2,3,3,4,4,5]

cnt=0

for i in permutations(a):

f=True

for j in range(len(i)-1):

if i[j]==i[j+1]:

f=False;

if f:

cnt+=1

print(cnt)

F.Chess

注意到想要安全,那么必须要避开所有的

的情况,因此我们暴力枚举,并且不用管中间有没有越子,因为如果越子,肯定已经不安全了,不影响答案。

n=int(input())

s=[]

for i in range(n):

t=input().split()

t[1]=int(t[1])

t[2]=int(t[2])

s.append(t)

def ATK(a,b):

if a[0]=='B':

return b[1]-b[2]==a[1]-a[2] or b[2]+b[1]==a[1]+a[2]

if a[0]=='R':

return a[1]==b[1] or a[2]==b[2]

return b[1]-b[2]==a[1]-a[2] or b[2]+b[1]==a[1]+a[2] or a[1]==b[1] or a[2]==b[2]

for i in range(n):

for j in range(n):

if i!=j and ATK(s[i],s[j]):

print("Attack!")

exit(0)

print("Safe!")

G.掷骰子

简单的动态规划问题,暴力+打表可以拿部分分。

代表前面

次,投的总和为

的方案总数。递推式子也很简单,枚举本次扔了那个点数。因为是长度为

的滑动窗口,所以可以省掉内部的

次循环(当然不省去正式比赛肯定也可以过)。

n,s=map(int,input().split())

dp=[[0]*(s+1) for i in range(n+1)]

mo=998244353

dp[0][0]=1

for i in range(1,n+1):

tmp=0

for j in range(s+1):

dp[i][j]=tmp%mo

if j>=6:

tmp-=dp[i-1][j-6]

tmp+=dp[i-1][j]

print(dp[n][s])

H.旅行

暴力

路径计数可水分。

“只有编号较小的城市能走向编号较大的城市”这句话很重要,说明了这个图是一个

(有向无环图)。我们可以定义

表示到第

个点的方案数。这里更新的顺序,我们只需要从

自然循环即可,因为到

的时候,所有连到

的点

必然已经确定了。

(当然你也可以用拓扑排序算法做这题,稍微麻烦咯)

n,m=map(int,input().split())

E=[[] for i in range(n+1)]

mo=998244353

for i in range(m):

a,b=map(int,input().split())

if a>b:

a,b=b,a

E[a].append(b)

ans=[0]*(n+1)

ans[1]=1

for i in range(n+1):

ans[i]%=mo

for j in E[i]:

ans[j]+=ans[i]

print(ans[n])

I.养猫

这里如果你手动模拟一下,发现其实是一个反向的“合并果子”问题。

合并果子是经典问题。根据贪心,或者“哈弗曼编码的思路”,每次取头最小的两个果子合并即可。

from queue import Queue

n=int(input())

a=sorted(list(map(int,input().split())))

class Queue:

def __init__(self):

self.d=[0]*n

self.hd=self.tl=0

def get(self):

self.hd+=1

return self.d[self.hd-1]

def put(self,x):

self.d[self.tl]=x

self.tl+=1

def empty(self):

return self.hd==self.tl

def front(self):

return self.d[self.hd]

Q1=Queue()

Q2=Queue()

for i in a:

Q1.put(i)

ans=0

for i in range(1,n):

if not Q1.empty() and (Q2.empty() or Q1.front()

u=Q1.get()

else:

u=Q2.get()

if not Q1.empty() and (Q2.empty() or Q1.front()

v=Q1.get()

else:

v=Q2.get()

Q2.put(u+v)

ans+=u+v

print(ans)

这里手工实现了队列。正常比赛其实没太大必要。

J.小明的赈灾计划

求一个子区间,使得其中异或和最大。首先根据前缀和思想,我们把问题转化为一堆数中,取两个数字,异或值最大。这里可以

水分。

正解的话这里暂时不作介绍,使用了一种叫做

的数据结构,将每个数字插入

中,再在

中二进制贪心。

class Trie:

def __init__(self,n):

self.ch=[None,[0,0]]

self.sz=1

def insert(self,x):

u=1

for i in range(31,-1,-1):

c=x>>i&1

if not self.ch[u][c]:

self.sz+=1

self.ch[u][c]=self.sz

self.ch.append([0,0])

u=self.ch[u][c]

def query(self,x):

u=1

ans=0

for i in range(31,-1,-1):

c=x>>i&1^1

if self.ch[u][c]:

u=self.ch[u][c]

ans|=1<

else:

u=self.ch[u][c^1]

return ans

n=int(input())

a=[0]+list(map(int,input().split()))

T=Trie(n)

T.insert(0)

for i in range(1,n+1):

a[i]^=a[i-1]

T.insert(a[i])

ans=0

for i in range(n+1):

ans=max(ans,T.query(a[i]))

print(ans)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值