受限于版权,不再复制题面。题目可以通过购买计蒜客蓝桥杯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)