第十三届蓝桥杯省赛B组
目录
试题A:排列字母
试题B:寻找整数
- 分析:一个个累加是不行的,跑一趟也跑不出来结果,先找规律,从大的开始,(满足大的可以满足小的,反之不行)
题解
i=1
while True:
flag=True
if i%49!=46:
flag=False
if i%48!=41:
flag=False
if i%47!=5:
flag=False
if i%46!=15:
flag=False
if i%45!=29:
flag=False
if flag:
print(i)
i+=1
-
输出结果为:4772009, 42909689, 81047369, 119185049,157322729, 195460409, 233598089
-
发现规律为等差数列:首项为4772009,差为38137680
-
枚举x
mod = [(2, 1), (14, 11), (26, 23), (38, 37),
(3, 2), (15, 14), (27, 20), (39, 23),
(4, 1), (16, 9), (28, 25), (40, 9),
(5, 4), (17, 0), (29, 16), (41, 1),
(6, 5), (18, 11), (30, 29), (42, 11),
(7, 4), (19, 18), (31, 27), (43, 11),
(8, 1), (20, 9), (32, 25), (44, 33),
(9, 2), (21, 11), (33, 11), (45, 29),
(10, 9), (22, 11), (34, 17), (46, 15),
(11, 0), (23, 15), (35, 4), (47, 5),
(12, 5), (24, 17), (36, 29), (48, 41),
(13, 10), (25, 9), (37, 22)]
i = 0
cha = 38137680
while True:
flag = True
num = cha*i+4772009
for x, y in mod:
if num % x != y:
flag = False
break
if flag:
print(num)
break
i += 1
- 最后结果为:2022040920220409
试题C:纸张尺寸
试题D:数位排序
试题E:蜂巢
试题F:消除游戏
暴力
alist = list(input())
for x in range(2 ** 64):
blist = [0] * len(alist) # 声明一个数组来标记边缘字符的下标
lens = len(blist) # 存储修改前的字符串数量
for i in range(1,len(blist)-1):
if alist[i] == alist[i-1] and alist[i] != alist[i+1]:
blist[i] = 1
blist[i + 1] = 1
if alist[i] == alist[i+1] and alist[i] != alist[i-1]:
blist[i] = 1
blist[i-1] = 1
clist = [] # 新的字符串
for i in range(lens):
if blist[i] == 0:#不是边缘字符
clist.append(alist[i])#把字符放到c中
alist = clist#更新alist,以便下一次迭代
if len(alist) == lens: # 如果字符串更新后的字符数量和更新前的字符数量相同,退出
break
s = "".join(alist)#把更新后的列表转换为字符串
if len(s) == 0:
print("EMPTY")
print(s)
- 87分
试题G:全排列的价值
- 分析:先对于输入的n找到他前面的每一个数,进行全排列(回溯),在对每一个全排列统计前面比自己小的数的个数
题解
def backtrack(nums, track, res):
if len(track) == len(nums):
res.append(track[:]) # 将当前排列添加到结果中
return
for i in range(len(nums)):
if nums[i] in track:
continue
track.append(nums[i]) # 做选择
backtrack(nums, track, res) # 递归
track.pop() # 撤销选择
# 输入n
n = int(input())
a = list(range(1, n+1))
res = []
track = []
backtrack(a, track, res)
total_sum = 0
for perm in res:
count = 0
for i in range(len(perm)):
for j in range(i + 1, len(perm)):
if perm[i] > perm[j]:
count += 1
total_sum += count
print(total_sum % 998244353)
-
18分
-
分析:1-n的全排列有n!种,对1-n中的两个数a,b(a<b),所以排列中有1/2是a在b前面,所以:ans=C(2,n) n! 1/2
正解
n = int(input())# 输入n
ans = 1# 初始化答案为1
for i in range(3, n + 1):# 计算阶乘除以2
ans = (ans * i) % 998244353#阶乘为1*2*...*n这里从3开始相当于原来的2被除掉了
ans = (ans * ((n * (n - 1) // 2) % 998244353)) % 998244353# 乘以C(2, n)
print(ans) # 输出答案
- 100分
试题H:技能升级
试题I:最长不下降子序列
试题J:最优清零方案
- 分析:先找连续不为0的M个数,减去1,记录次数,最后在对一个数减去1,记录次数
代码
n,m=map(int,input().split())
a=list(map(int,input().split()))
count=0
for i in range(n):
for j in range(i+1):
if a[i]>1 and a[j]>=1:
a[i]-=1
a[j]-= 1
count+=1
print(a)
for i in range(n):
count+=a[i]
print(count)
- 超时
题解:滑动窗口
n,k=map(int,input().split())
a=[int(i) for i in input().split()]
count=0#计数
i=0#滑动窗口左指针,不用定义右指针因为窗口大小固定,右指针在左指针基础上加上窗口大小即可
#并且滑动窗口的时候只需要改变左指针即可,右指针由左指针改变
while i<n-k+1:
c =min(a[i:i+k])#c为滑动窗口内的最小值
count+=c#这个窗口内一起减1的次数
if c!=0:
for j in range(i,i+k):#滑动窗口内的所有数都减去c
a[j]-=c
if a[j]==0:#当有一个位置减c为0时,说明这个位置就是滑动窗口内的最小值,下一个滑动窗口从它的下一个位置开始
i=j+1#更新滑动窗口左指针
for i in range(n):
if a[i]!=0:#把最后数组不是0的加起来,表示还需要单独减多少次
count+=a[i]
print(count)
- 83分