第十三届蓝桥杯省赛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分
posted @ 2024-03-20 12:57  Frommoon  阅读(22)  评论(0编辑  收藏  举报