蓝桥杯作为国内知名的程序设计竞赛,其题目往往融合了数学建模与算法设计的双重挑战。2015年省赛AB组的这道"垒骰子"题目,表面看是一个排列组合问题,实则考察选手对动态规划优化和矩阵快速幂的掌握程度。
题目要求计算n个骰子垂直垒放时相邻骰子接触面数字不互斥的排列总数。具体约束条件包括:
最直观的解法是采用DFS递归枚举所有可能的排列组合。对于每个骰子,考虑其朝上面数字与下方骰子朝下面数字是否满足非互斥条件。这种方法时间复杂度为O(6^n),当n较大时(如题目中的n≤10^9)完全不可行。
python复制def dfs(current, top, n):
if current == n:
return 1
count = 0
for num in range(1,7):
if not conflict[top][num]:
count += dfs(current+1, num, n)
return count % MOD
观察到每个骰子的状态只依赖于前一个骰子的朝上面数字,可以使用DP进行优化:
python复制dp = [[0]*7 for _ in range(n+1)]
# 初始化第一个骰子
for num in range(1,7):
dp[1][num] = 1
for i in range(2,n+1):
for top in range(1,7):
for num in range(1,7):
if not conflict[top][num]:
dp[i][num] += dp[i-1][top]
dp[i][num] %= MOD
这种DP解法时间复杂度为O(n*6^2),对于n=10^9仍然无法承受。
将骰子数字之间的关系表示为6×6的转移矩阵T:
例如,若数字1与2互斥,则T[1][2]=T[2][1]=0
观察到DP递推式可以表示为:
dp[n] = T^(n-1) * dp[1]
利用矩阵快速幂可以在O(log n)时间内计算矩阵的高次幂。具体步骤:
python复制def matrix_mult(a, b):
res = [[0]*6 for _ in range(6)]
for i in range(6):
for j in range(6):
for k in range(6):
res[i][j] = (res[i][j] + a[i][k]*b[k][j]) % MOD
return res
def matrix_pow(mat, power):
result = [[1 if i==j else 0 for j in range(6)] for i in range(6)]
while power > 0:
if power % 2 == 1:
result = matrix_mult(result, mat)
mat = matrix_mult(mat, mat)
power //= 2
return result
python复制def solve():
n, m = map(int, input().split())
conflict = [[False]*7 for _ in range(7)]
for _ in range(m):
a, b = map(int, input().split())
conflict[a][b] = conflict[b][a] = True
# 构建转移矩阵
T = [[0]*6 for _ in range(6)]
for i in range(6):
for j in range(6):
if not conflict[i+1][j+1]:
T[i][j] = 1
# 矩阵快速幂
mat_n = matrix_pow(T, n-1)
# 计算结果
total = 0
for i in range(6):
for j in range(6):
total = (total + mat_n[i][j]) % MOD
# 考虑骰子旋转 (4^n种可能)
rotation = pow(4, n, MOD)
ans = (total * rotation) % MOD
print(ans)
构建转移矩阵时需注意:
每个骰子在确定上下两个面后,侧面有4种旋转方式,因此总方案数需要乘以4^n。这里可以使用快速幂计算:
python复制pow(4, n, MOD)
| 方法 | 时间复杂度 | 可处理的n范围 |
|---|---|---|
| 暴力递归 | O(6^n) | n≤10 |
| 动态规划 | O(n*36) | n≤10^6 |
| 矩阵快速幂 | O(log n*6^3) | n≤10^18 |
矩阵快速幂将线性时间复杂度优化为对数级,是处理这类递推问题的利器。
这种解法可推广到以下场景:
例如:
提示:当遇到n极大的计数问题时,先分析状态转移是否可以用矩阵表示,再考虑快速幂优化。