临近考试,从网友那拿到了这份题,抽时间慢慢写题解 (只写我没练过的题型,其它题型可以看我其它博客)
小明的彩灯
【题目描述】
小明拥有 N 个彩灯,第i个彩灯的初始亮度为 。
小明将进行 Q 次操作,每次操作可选择一段区间,并使区间内彩灯的亮度+x (x 可能为负数)
求 Q 次操作后每个彩灯的亮度 (若彩灯亮度为负数则输出0)。
【输入描述】
第一行包含两个正整数 N,Q,分别表示彩灯的数量和操作的次数。
第二行包含 N 个整数,表示彩灯的初始亮度。
接下来 Q 行每行包含一个操作,格式如下:
l r x,表示将区间 l ~ r 的彩灯的亮度 + x。
【输出描述】
输出共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 件衣服的邮费为 元,染色厂会按照小明的要求将其中一部分衣服染成同一种任意的颜色,之后将衣服寄给小明,请问小明要将 n 件衣服染成不同颜色的最小代价是多少?
【输入描述】
第一行为一个整数 n,表示衣服的数量
第二行包括n个整数 表示第 i 件衣服的邮费为
元
【输出描述】
输出一个整数表示小明所要花费的最小代价
【样例】
输入 | 输出 |
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
【输出描述】
输出共T行,每行包含一个整数,表示答案,结果保留俩位小数。
【样例】
输入 | 输出 |
2 1 12 | 1.00 37.24 |
【解析及代码】
定义一维列表 dp,dp[i] 表示已扔出 i 个不重复面时,到达终态 (每个面都出现过) 的期望次数,显然有 dp[n] = 0
dp[i] 由 3 部分组成:
- 扔出 1 次
- 如果是不重复面 (概率
),则加上扔出 i 个面的期望
- 如果是重复面 (概率
),则加上扔出 i+1 个面的期望
化简得:
最后答案即为 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}')