数组

python没有严格意义上的数组,一般用list。但是开二维数组还是需要简单注意一下的。

首先是需要了解一下python的list的*运算符,列表重复(List Repetition)。

1
2
3
lst = [1, 2, 3]
result = lst * 3
print(result)  # 输出: [1, 2, 3, 1, 2, 3, 1, 2, 3]

注意:如果 n 是 0 或负数,结果会是一个空列表。

如果列表中的元素是可变对象(如列表、字典等),重复操作会导致共享引用问题。(备注一下,此时被复制的元素是整个list脱去一层后的那一层,比如[0]->0,[[0]] 才是 [0])

例如:

1
2
3
4
5
lst = [[0]] * 3
print(lst)  # 输出: [[0], [0], [0]]
lst[0][0] = 1
print(lst)  # 输出: [[1], [1], [1]],所有子列表都被修改了
# 这是因为 * 复制的是引用,而不是创建新的对象。

然后二维数组就有两种写法。

1
2
3
4
5
# 一维数组
a = [0] * 10086
# 二维数组
f = [[0] * cols for _ in range(rows)]
f = [[0 for _ in range(cols)] for _ in range(rows)

求n!中质数的出现次数

质数 $ p $ 在 $ n! $ 中的出现次数可以通过以下步骤计算:

  1. 初始化总和:设次数 $ v_p(n!) = 0 $。
  2. 逐次除以 $ p $ 的幂: 从 $ k = 1 $ 开始,依次计算 $ \left\lfloor \frac{n}{p^k} \right\rfloor $(即 $ n $ 除以 $ p^k $ 的商向下取整),并将结果累加到总和 $ v_p(n!) $ 中。
  3. 终止条件:当 $ p^k > n $ 时,后续项均为 0,停止计算。

公式表示

$$ v_p(n!) = \sum_{k=1}^{\infty} \left\lfloor \frac{n}{p^k} \right\rfloor $$

原理

  • $ \left\lfloor \frac{n}{p} \right\rfloor $ 统计了 $ 1 \sim n $ 中至少含有一个 $ p $ 因子的数的个数。
  • $ \left\lfloor \frac{n}{p^2} \right\rfloor $ 统计了至少含两个 $ p $ 因子的数的个数(每个额外贡献一次)。
  • 以此类推,每次累加更高幂次的贡献,最终总和即为 $ p $ 在 $ n! $ 中的总次数。

示例
$$ ( n = 10 ),质数 ( p = 3 ) 时:

\left\lfloor \frac{10}{3} \right\rfloor + \left\lfloor \frac{10}{9} \right\rfloor = 3 + 1 = 4 $$ 验证:$ 10! = 3628800 = 2^8 \times 3^4 \times 5^2 \times 7 $,确实 $ 3$出现 4 次。

结论:通过逐次除以 $ p $ 的幂并求和,即可准确计算质数 $ p $ 在 $ n! $ 中的次数。

二维矩阵相等

1
2
3
4
5
6
7
8
9
n, m = map(int, input().split())
a = [input() for _ in range(n)]
b = [input() for _ in range(m)]
for i in range(n - m + 1):
    for j in range(n - m + 1):
        if all(a[i + k][j:j + m] == b[k] for k in range(m)):
            print('Yes')
            exit()
print('No')

sequence[start : end : step] # step 默认为 1 规则

  1. start: 起始索引(包含)
  2. end: 结束索引(不包含)
  3. 索引可以是负数,表示从末尾开始计数
  4. 省略规则:
    • [:] - 复制整个序列
    • [start:] - 从start到末尾
    • [:end] - 从开始到end-1
    • [:-1] - 除了最后一个元素的所有元素

all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 True,如果是返回 True,否则返回 False。

python只有小根堆,大根堆用负数实现,但是注意python的地板除的cpp的区别(//表示“地板除”(floor division),即两个数相除后向下取整(取不大于结果的最大整数)而cpp的/当操作数为整数时,执行的是截断除法(truncation division),即直接舍去小数部分(向零靠拢))

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import heapq

# 1. 基本操作
heap = []  # 创建一个空堆

# 添加元素
heapq.heappush(heap, 4)
heapq.heappush(heap, 1)
heapq.heappush(heap, 7)
heapq.heappush(heap, 3)

print("堆的内容:", heap)  # [1, 3, 7, 4]

# 弹出最小元素
smallest = heapq.heappop(heap)
print("弹出的最小元素:", smallest)  # 1
print("弹出后的堆:", heap)  # [3, 4, 7]

# 查看堆顶元素但不删除
peek = heap[0]
print("堆顶元素:", peek)  # 3

# 2. 高级用法
numbers = [10, 4, 8, 3, 5, 9]

# 将列表转换为堆
heapq.heapify(numbers)
print("转换后的堆:", numbers)  # [3, 4, 8, 10, 5, 9]

# 获取最小的3个元素
smallest_three = heapq.nsmallest(3, numbers)
print("最小的三个元素:", smallest_three)  # [3, 4, 5]

# 获取最大的3个元素
largest_three = heapq.nlargest(3, numbers)
print("最大的三个元素:", largest_three)  # [10, 9, 8]