【蓝桥杯PythonB组备赛】【Acwing周赛】第91场非常详细的过程思路分析理解分享Python解

好难哈哈哈我依旧只做对了第一题,第二题在比赛结束后才做出来……

不过没关系每天努力一点啦~

分享一下个人做的解析,供大家参考,一起努力哇!

目录

A    AcWing 4861. 构造数列

1.题目描述

2.思路分析

3.代码实现

B    AcWing 4862. 浇花

1.题目描述

2.思路分析

3.代码实现

C    AcWing 4863. 构造新矩阵

1.题目描述

2.思路分析

3.代码实现

4.算法知识点补充——二分模板


A    AcWing 4861. 构造数列

1.题目描述

2.思路分析

本题算法:贪心

主要思路:

  • 将n看成字符串,遍历其中每一个元素n[i] 
  • 若n[i]为0,不用管
  • 若n[i]不为0,就在n[i]后面添上对应的0,并放入构造数列l中

        如8009中的8,添上三个0变成8000,然后将8000放入构造数列l中

3.代码实现

T = int(input())
for _ in range(T):
    n = input()
    l = []
    for i in range(len(n)):
        if int(n[i]):
            l.append(n[i] + '0' * (len(n) - (i + 1)))
    print(len(l))
    print(' '.join(l))

B    AcWing 4862. 浇花

1.题目描述

2.思路分析

本题算法:暴力(枚举)

这题我一开始琢磨了半天没理解题目,不明白[ai,bi]什么意思。

后来终于意识到这是个区间:从第ai天到第bi天。

(我是傻子……)

过程思路:

  • 定义一个flag,默认为True(表示花没死)
  • 遍历a[i],b[i]的元素

flag永远为True(花一直没死)的条件:

1.前一个人和后一个人浇花连续不断  ==>  遍历a[i],b[i]时一直满足b[i] + 1 == a[i + 1]

举例:前一个人在第3天浇水了,后一个人在第4天必须浇水,

           如果没有在第4天浇水,第5天才浇水,花就死了。

           如果后一个人还是在第3天浇水,花也死了。

           所以必须满足3+1 == 4,花才不会死

2.第一个人和最后一个人必须分别在第1天和最后一天浇一次水 ==> a[1] == 1 and b[m] == n

所以我们要进行分类讨论: 

  • 水浇多了: 
    if b[i] == a[i + 1]:
        flag = False
        print(a[i + 1], a.count(a[i + 1]) + 1)
        break

如果前一个人在第3天浇水,后一个还在第3天浇水,

花就在第三天死了,因为浇了两次水。(flag = False)

如果之后的人还是在第3天浇水,那就浇了三次水,

所以我们数一下有几个在第3天浇水的人。

(至于为什么+1可以看一下下面的例子自己推敲一下哈)

'''
1 2
3 3 (i)
3 3 (i+1)
3 5
'''
  • 没浇水:

    elif a[i + 1] - b[i] > 1:
        flag = False
        print(b[i] + 1, 0)
        break

 如果前一个人在第3天浇水,后一个人在第5天浇水,(a[i + 1] - b[i] > 1)

那么第四天没人浇水,花就在第四天死了(b[i] + 1)

 一旦水浇多或者没浇水,花就死了,所以不需要再遍历了,直接break跳出循环

  • 水没浇多也没浇少,但是最后一天(或多天)没浇水:
    if flag:
        if b[m] == n:
            print("OK")
        else:
            print(b[m] + 1, 0)

    (第一天不用讨论了因为我们的a,b是从0开始的,在遍历时已经判断过了)

    如果最后一个人的浇水天数里没有n,说明最后一天(或多天)没浇水。

    比如10天假期,最后一个人在第8天浇了水之后就不浇了,那么后两天都没浇水,

    所以花在第9天(b[m] + 1)死了

ps:本题也可用差分

3.代码实现

n, m = map(int, input().split())
a, b = [0] * (m + 1), [0] * (m + 1)
for i in range(1, m + 1):
    a[i], b[i] = map(int, input().split())
flag = True
for i in range(m):
    if b[i] == a[i + 1]:
        flag = False
        print(a[i + 1], a.count(a[i + 1]) + 1)
        break
    elif a[i + 1] - b[i] > 1:
        flag = False
        print(b[i] + 1, 0)
        break
if flag:
    if b[m] == n:
        print("OK")
    else:
        print(b[m] + 1, 0)

C    AcWing 4863. 构造新矩阵

1.题目描述

2.思路分析

本题算法:二分

过程思路:

1. 构成新矩阵后,我们可以确定一个最大的整数 L,使得新矩阵中每一列都至少存在一个元素不小于 L。

 将上面这句话转换为:确定一个最大的整数 L,使得新矩阵中每一列的最大值>=L

2.本题数据量非常大,所以采取二分法来优化。

3.虽然说不超过n-1行,但是我们能多选绝对不少选,所以我们把n-1行都选上,也就是把>=L的值都圈上。(因为多选了没事,即使这一行数字比较小,我们也不需要管它,我们的目光是集中在大值上的;但是少选可能会漏掉一些关键的大值) 

ps:圈定义bool类型来表示

4.运用抽屉原理(也可以直接想)

当一行有2个元素都>=L(两个圈),那就选这行,因为这一行满足了两列

那么剩下的n-2列,不管我选哪一行,当前L都成立

即:

  • 1行盖2列
  • n-2行盖n-2列

(当然前提是:每一列都至少有一个元素>=L,否则必定不成立,此处可以另写一个判断)

3.代码实现

T = int(input())
for _ in range(T):
    kong = input()
    m, n = map(int, input().split())
    p, max_p = [], []
    for i in range(m):
        p.append(list(map(int, input().split())))
        max_p.append(max(p[i]))
    # 二分求最优解(L最大值)
    l = 1
    r = max(max_p)
    while l < r:
        L = (l + r + 1) // 2  # 要+1,不然死循环
        # 求当前L成不成立(该矩阵满不满足当前L)
        flag = [[False] * n for _ in range(m)]  # 默认矩阵元素都没有圈
        succeed = False  # 默认不成立
        # 将>=L的元素都圈上
        for i in range(m):
            for j in range(n):
                if p[i][j] >= L:
                    flag[i][j] = True
            # 如果这一行有两个及以上的元素被圈上了,当前L可能成立
            if flag[i].count(True) >= 2:
                succeed = True
        # 如果一列上没有一个圈,必不成立
        for i in range(n):
            lie = []  # 每一列
            for j in range(m):
                lie.append(flag[j][i])
            if lie.count(True) == 0:
                succeed = False
                break
        if succeed:
            l = L  # 成立的,所以不+1,万一此时就是最优解,加了个1就没了
        else:
            r = L - 1  # 当前L不成立
    print(r)

4.算法知识点补充——二分模板

模板一:

while l < r:
    mid = l + r >> 1  # (l + r) // 2
    if check(mid):  # check()判断mid是否成立
        r = mid
    else:
        l = mid + 1

模板二:

while l < r:
    mid = l + r + 1 >> 1
    if check(mid):
        l = mid
    else:
        r = mid - 1

细节处(很关键): 

只要是往左找答案,就用第一个模板,mid不用加一,r=mid,l加一;
只要是往右找答案,就用第二个模板,mid要加一,l=mid,r要减一;

这里的细节要着重理解记忆!!!

本题是往右找答案,mid+1是防止死循环,l不加1是防止错过正确答案

此处模板参考:二分查找 & 二分答案 万字详解,超多例题,带你学透二分。_小酒窝.的博客-CSDN博客_二分查找题目

感谢大佬~ 


最后一题分析参考y总的哈,大家也可以直接看y总的讲解。

如有帮助可以点赞收藏嘛~

如有不足或不解之处欢迎评论留言~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃头小二

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值