📅  最后修改于: 2023-12-03 15:42:21.106000             🧑  作者: Mango
此题目为“置换矩阵”的题目。
给定一个 $n$ 阶置换矩阵 $A$。按顺序询问 $m$ 次,每次输入一个矩阵 $B$,需要求出 $AB$。矩阵大小为 $n \times n$,矩阵元素均为 $0$ 或 $1$。
答案对 $10^9+7$ 取模,结果输出到标准输出。
由于本题的答案对 $10^9 + 7$ 取模,所以考虑使用矩阵快速幂求解。
首先将题意转换为:给出 $n$ 个初始位置 $p_1,p_2,...,p_n$ 和 $n$ 个最终位置 $q_1,q_2,...,q_n$,表示在 $B$ 矩阵上,原来在 $i$ 行 $j$ 列的元素现在在 $p_i$ 行 $p_j$ 列,问最终所在位置为 $q_i$ 行 $q_j$ 列的元素值是多少。
我们可以枚举最终位置,也就是枚举 $q_k$,然后统计有多少对初始位置 $(i,j)$ 满足 $(p_i,p_j) = (q_k,q_l)$。设这个数量为 $x_k$,则最终矩阵的第 $k$ 行 $l$ 列元素的值就是 $x_k$。
将问题转化之后,我们发现矩阵乘法就是我们要计算的函数。
设 $f(i,j)$ 表示原来在 $i$ 行 $j$ 列的元素最后停留在 $k$ 行 $l$ 列的方案数,则有 $f(k,l) = \sum\limits_{i=1}^n \sum\limits_{j=1}^n f(i,j) [p_i=k, p_j=l]$。
注意到 $f$ 是一个关于矩阵 $B$ 的函数,我们可以将这个式子写成矩阵乘法的形式,从而将矩阵快速幂算法进行应用。
最后,需要注意的是,矩阵快速幂过程中需要开一个新的矩阵用于储存答案,因为在本题中,$A$ 矩阵和 $B$ 矩阵的大小是 $n^2$,两个矩阵相乘会得到一个大小为 $n^4$ 的矩阵,如果直接更新 $B$ 矩阵,会导致内存错误。因此,我们需要同时维护两个矩阵,一个作为中间矩阵,一个作为结果矩阵。
下面为 Python3 代码实现:
MOD = 1000000007
def multiply(A, B):
n = len(A)
C = [[0] * n for i in range(n)]
for i in range(n):
for j in range(n):
for k in range(n):
C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % MOD
return C
def quick_power(A, k):
n = len(A)
res = [[0] * n for i in range(n)]
for i in range(n):
res[i][i] = 1
while k > 0:
if k & 1:
res = multiply(res, A)
A = multiply(A, A)
k >>= 1
return res
def solve(n, m, A, query):
# 统计初始位置和最终位置
L = [0] * n
R = [0] * n
for i in range(n):
for j in range(n):
if A[i][j]:
L[i] += 1
R[j] += 1
# 构造矩阵
# f(i,j) 表示原来在 (i,j) 的元素现在在 (k,l) 的方案数
f = [[0] * (n ** 2) for i in range(n ** 2)]
for k in range(n):
for l in range(n):
idx = k * n + l
for i in range(n):
for j in range(n):
if A[i][j]:
f[i*n+j][idx] = 1
# 统计答案
B = quick_power(f, m)
ans = [0] * (n ** 2)
for k in range(n):
for l in range(n):
idx = k * n + l
for i in range(n):
for j in range(n):
if query[k][l] and query[i][j]:
p = i * n + j
x = B[p][idx]
ans[idx] = (ans[idx] + x) % MOD
# 输出答案
for i in range(n):
for j in range(n):
print(ans[i*n+j], end=' ')
print()
返回的 markdown 代码片段为:
```python
MOD = 1000000007
def multiply(A, B):
n = len(A)
C = [[0] * n for i in range(n)]
for i in range(n):
for j in range(n):
for k in range(n):
C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % MOD
return C
def quick_power(A, k):
n = len(A)
res = [[0] * n for i in range(n)]
for i in range(n):
res[i][i] = 1
while k > 0:
if k & 1:
res = multiply(res, A)
A = multiply(A, A)
k >>= 1
return res
def solve(n, m, A, query):
# 统计初始位置和最终位置
L = [0] * n
R = [0] * n
for i in range(n):
for j in range(n):
if A[i][j]:
L[i] += 1
R[j] += 1
# 构造矩阵
# f(i,j) 表示原来在 (i,j) 的元素现在在 (k,l) 的方案数
f = [[0] * (n ** 2) for i in range(n ** 2)]
for k in range(n):
for l in range(n):
idx = k * n + l
for i in range(n):
for j in range(n):
if A[i][j]:
f[i*n+j][idx] = 1
# 统计答案
B = quick_power(f, m)
ans = [0] * (n ** 2)
for k in range(n):
for l in range(n):
idx = k * n + l
for i in range(n):
for j in range(n):
if query[k][l] and query[i][j]:
p = i * n + j
x = B[p][idx]
ans[idx] = (ans[idx] + x) % MOD
# 输出答案
for i in range(n):
for j in range(n):
print(ans[i*n+j], end=' ')
print()