蓝桥杯【夺奖宝典】Python

临近考试,从网友那拿到了这份题,抽时间慢慢写题解 (只写我没练过的题型,其它题型可以看我其它博客)

小明的彩灯

【题目描述】

        小明拥有 N 个彩灯,第i个彩灯的初始亮度为 a_i

        小明将进行 Q 次操作,每次操作可选择一段区间,并使区间内彩灯的亮度+x (x 可能为负数)

        求 Q 次操作后每个彩灯的亮度 (若彩灯亮度为负数则输出0)。

【输入描述】

        第一行包含两个正整数 N,Q,分别表示彩灯的数量和操作的次数。

        第二行包含 N 个整数,表示彩灯的初始亮度。

        接下来 Q 行每行包含一个操作,格式如下:

        l r x,表示将区间 l ~ r 的彩灯的亮度 + x。

        1 \leq N,Q\leq 5 \times 10^5, 0\leq a\leq 10^{\circ}, 1\leq l\leq r \leq N, -10^9< a \leq 10^9

【输出描述】

        输出共1行,包含N个整数,表示每个彩灯的亮度。

【样例】

输入输出
5 3
2 2 2 1 5
1 3 3
4 5 5
1 1 -100
0 5 5 6 10

【解析及代码】

首先排除暴力通过测试的可能性

题目需要操作的是,对某一个区间内的彩灯亮度进行批量加减操作,所以转为对差分数列进行个别加减操作。该差分数列记录的是相邻两个彩灯的亮度差距 (后 - 前),首元素为第一个彩灯的亮度。往后叠加 n-1 次,可得第 n 个彩灯的亮度

把控边界条件,得出代码如下:

import itertools as it

n, q = map(int, input().split())
light = list(map(int, input().split()))
# 得到差分数列
for i in range(n - 1, 0, -1): light[i] -= light[i - 1]

for i in range(q):
    l, r, x = map(int, input().split())
    light[l - 1] += x
    # 当有边界不是末尾
    if r < n: light[r] -= x

# 求前缀和
print(*map(lambda i: max(0, i), it.accumulate(light)))

小明的衣服

【题目描述】

        小明买了 n 件白色的衣服,他觉得所有衣服都是一种颜色太单调,希望对这些衣服进行染色,每次染色时,他会将某种颜色的所有衣服寄去染色厂,第 i 件衣服的邮费为 a_i 元,染色厂会按照小明的要求将其中一部分衣服染成同一种任意的颜色,之后将衣服寄给小明,请问小明要将 n 件衣服染成不同颜色的最小代价是多少?

【输入描述】

        第一行为一个整数 n,表示衣服的数量

        第二行包括n个整数 a_1, a_2... a_n 表示第 i 件衣服的邮费为 a_i

        1 \leq n \leq 10^5,1 \leq a_i\leq 10^9

【输出描述】

        输出一个整数表示小明所要花费的最小代价

【样例】

输入输出
5
5 1 3 2 1 
25

【解析及代码】

每次将一堆衣服 (同颜色) 寄过去,但是只有其中一部分衣服染成另一种颜色,也就是 一种颜色 → 两种颜色

初始输入是 n 件颜色一样的衣服,输出是 n 件 n 种颜色的衣服

将输入输出反过来,染衣服的过程也变成了 两种颜色 → 一种颜色

若输入是 [5, 1, 3, 2, 1],则结果是 25:

  • 取 1 和 1 的两件衣服染成一样颜色
  • 取 (1 + 1) 和 2 的三件衣服染成一样颜色
  • 取 (1 + 1 + 2) 和 3 的四件衣服染成一样颜色
  • 取 (1 + 1 + 2 + 3) 和 5 的五件衣服染成一样颜色

其实这就是个构建哈夫曼树的过程,代码如下:

import heapq

_ = input()
# 各件衣服的邮费
cost = list(map(int, input().split()))
heapq.heapify(cost)

res = 0
while len(cost) > 1:
    # 取前 2 个最小的价格
    min_s = sum(heapq.heappop(cost) for _ in range(2))
    res += min_s
    heapq.heappush(cost, min_s)

print(res)

骰子

【题目描述】

        投一个 n 面的骰子,问每一个面都至少被甩到过一次的次数期望是多少?

【输入描述】

        第1行为一个整数T,表示测试数据数量。接下来的T行每行包含一个正整数N

        1<T\leq 10^3, 1\leq N<10^3

【输出描述】

        输出共T行,每行包含一个整数,表示答案,结果保留俩位小数。

【样例】

输入输出
2
1
12
1.00
37.24

【解析及代码】

定义一维列表 dp,dp[i] 表示已扔出 i 个不重复面时,到达终态 (每个面都出现过) 的期望次数,显然有 dp[n] = 0

dp[i] 由 3 部分组成:

  • 扔出 1 次
  • 如果是不重复面 (概率 \frac{n-i}{n}),则加上扔出 i 个面的期望
  • 如果是重复面 (概率 \frac{i}{n}),则加上扔出 i+1 个面的期望

dp[i]=1+\frac{n-i}{n}dp[i+1]+\frac{i}{n}dp[i]

化简得:

dp[i]=dp[i+1]+\frac{n}{n-i}

最后答案即为 dp[0]

for _ in range(int(input())):
    n = int(input())
    dp = [0.] * (n + 1)
    # dp[i]: 已扔出 i 个面, 到达终态的数学期望
    for i in range(n - 1, -1, -1):
        dp[i] = dp[i + 1] + n / (n - i)
    print(f'{dp[0]:.2f}')
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

荷碧TongZJ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值