Luogu P1990 覆盖墙壁

题目分析与思路

本题要求我们计算用 \(1 \times 2\) 和 L 型砖块铺满一个 \(2 \times N\) 墙壁的方案数。这是一个典型的组合计数问题,在网格上进行填充,通常可以采用动态规划(Dynamic Programming, DP)来解决。我们通常会设 dp[i] 为铺满 \(2 \times i\) 墙壁的方案数。一个初步的想法是,考虑最右边一列是如何被覆盖的:

  1. 如果用一个竖直的 \(1 \times 2\) 砖块覆盖第 \(i\) 列,那么问题就转化为求解铺满 \(2 \times (i-1)\) 墙壁的方案数,即 dp[i-1]
  2. 如果用两个水平的 \(1 \times 2\) 砖块覆盖第 \(i-1\)\(i\) 列,那么问题就转化为求解铺满 \(2 \times (i-2)\) 墙壁的方案数,即 dp[i-2]

这样我们会得到一个类似斐波那契数列的递推式:dp[i] = dp[i-1] + dp[i-2]。但这个递推式是不完整的。为什么呢?让我们来验证一下:

  • dp[1] = 1 (1个竖直砖块)
  • dp[2] = 2 (2个竖直砖块 或 2个水平砖块)
  • 根据上述递推式,dp[3] = dp[2] + dp[1] = 2 + 1 = 3
  • 然而,题目样例明确指出 \(N=3\) 时有 \(5\) 种方案。

这说明我们遗漏了某些情况。遗漏的正是那些由 L 型砖块构成的铺法。L 型砖块的特点是它无法整齐地填满最右侧的若干列,它总是会留下一个“缺口”,导致墙壁的填充边界不是一条直线。因此,我们需要一个更复杂的状态定义来描述这些带有“缺口”的中间状态。

状态定义与递推

为了解决上述问题,我们需要引入辅助的DP状态。我们观察到,在从左到右铺砖的过程中,填充边界可能不是一条直线,会缺少一个角。我们定义两种状态:

  1. \(f(n)\)完全铺满一个 \(2 \times n\) 矩形墙壁的方案数。这是我们最终要求解的目标。
  2. \(g(n)\):铺满一个 \(2 \times n\) 的区域,但右上角(或右下角)缺少一个 \(1 \times 1\) 单元的方案数。由于对称性,这两种缺口情况的方案数是相同的。

下图展示了这两种状态:

      f(n)            g(n) (右上缺口)
  +-------+         +-------+
  |#######|         |###### |
  |#######|         |#######|
  +-------+         +-------+
   <-- n -->         <-- n -->

现在,我们来构建这两个状态之间的递推关系。

推导 \(f(n)\)

要得到一个完整\(2 \times n\) 墙壁,我们考虑最右侧是如何被填满的:

  • 情况 A:在一个完整的 \(2 \times (n-1)\) 墙壁(\(f(n-1)\) 种方案)右侧,加上一个竖直的 \(1 \times 2\) 砖块。

    f(n-1)       +  V  ->    f(n)
    +---------+     +---+   +-----------+
    |#########|     | V |   |#########V|
    |#########|     | V |   |#########V|
    +---------+     +---+   +-----------+
    

    贡献:\(f(n-1)\)

  • 情况 B:在一个完整的 \(2 \times (n-2)\) 墙壁(\(f(n-2)\) 种方案)右侧,加上两个水平的 \(1 \times 2\) 砖块。

    f(n-2)     +  HH  ->    f(n)
    +-------+    +----+    +-----------+
    |#######|    | HH |    |#######HH|
    |#######|    | HH |    |#######HH|
    +-------+    +----+    +-----------+
    

    贡献:\(f(n-2)\)

  • 情况 C:在一个 \(2 \times (n-1)\) 但右上角有缺口的墙壁(\(g(n-1)\) 种方案)上,用一个 L 型砖块恰好补上缺口并覆盖第 \(n\) 列。

    g(n-1)       +  L   ->    f(n)
    +---------+    +---+     +-----------+
    |######## |    |LL |     |########LL|
    |#########|    | L |     |#########L|
    +---------+    +---+     +-----------+
    

    贡献:\(g(n-1)\)

  • 情况 D:对称地,在一个 \(2 \times (n-1)\) 但右下角有缺口的墙壁(同样是 \(g(n-1)\) 种方案)上,用一个旋转过的 L 型砖块填补。

    g(n-1)       +  L'  ->    f(n)
    +---------+    +---+     +-----------+
    |#########|    | L |     |#########L|
    |######## |    |LL |     |########LL|
    +---------+    +---+     +-----------+
    

    贡献:\(g(n-1)\)

综合以上四种情况,我们得到 \(f(n)\) 的递推式:\(f(n) = f(n-1) + f(n-2) + 2g(n-1)\)

推导 \(g(n)\)

\(g(n)\) 是填满了 \((x, y)\) 其中 \(0 \le x \le 1, 0 \le y < n\) 除了 \((0, n - 1)\) 的方案数。

  • 来源一:从 \(g(n-1)\) 出发。\(g(n-1)\) 填满了 \(0 \le y < n-1\) 的格子,除了 (0, n-2)。我们要在其右侧添加砖块形成 \(g(n)\)。可以在 \((1, n-2)\)\((1, n-1)\) 处放置一个水平砖块。这样,\((0, n-1)\) 保持为空,\((0, n-2)\) 被填上。这需要 \((0, n-2)\) 之前是空的,这正是 \(g(n-1)\) 的状态,贡献了 \(g(n-1)\)
  • 来源二:从 \(f(n-2)\) 出发。\(f(n-2)\) 是一个完整的 \(2 \times (n-2)\) 矩形。在其右侧加一个 L 型砖块,覆盖 \((1, n-2), (1, n-1), (0, n-1)\)。这样就完美地构成了 \(g(n)\) 的形状。

综合以上两个来源,我们得到 \(g(n)\) 的递推式:\(g(n) = g(n-1) + f(n-2)\)

递推关系化简

我们现在有了一个递推方程组:

\[f(n) = f(n-1) + f(n-2) + 2g(n-1) \quad (1) \]

\[g(n) = g(n-1) + f(n-2) \quad (2) \]

我们可以通过代数变换消去 \(g(n)\),得到一个只关于 \(f(n)\) 的递推式。由 \((1)\) 式可得:

\[2g(n-1) = f(n) - f(n-1) - f(n-2) \quad (A) \]

\((A)\) 式中的 \(n\) 替换为 \(n-1\),可得:

\[2g(n-2) = f(n-1) - f(n-2) - f(n-3) \quad (B) \]

\((2)\) 式可得:

\[g(n-1) = g(n-2) + f(n-3) \]

两边同乘以 \(2\),得:

\[2g(n-1) = 2g(n-2) + 2f(n-3) \quad (C) \]

\((A)\) 式和 \((B)\) 式代入 \((C)\) 式:

\[f(n) - f(n-1) - f(n-2) = (f(n-1) - f(n-2) - f(n-3)) + 2f(n-3) \]

化简上式:

\[f(n) - f(n-1) - f(n-2) = f(n-1) - f(n-2) + f(n-3) \]

\[f(n) = 2f(n-1) + f(n-3) \]

这是一个简洁的、只关于 \(f\) 的三阶线性递推关系。

边界条件确定

为了使用递推式 \(f(n) = 2f(n-1) + f(n-3)\),我们需要确定初始值 \(f(0), f(1), f(2)\)

  • \(f(0)\):铺满 \(2 \times 0\) 的墙壁。只有一种方法:什么都不铺。所以 \(f(0) = 1\)

  • \(f(1)\):铺满 \(2 \times 1\) 的墙壁。只有一种方法:放置一个竖直的 \(1 \times 2\) 砖块。所以 \(f(1) = 1\)

  • \(f(2)\):铺满 \(2 \times 2\) 的墙壁。有两种方法:

    1. 两个竖直的 \(1 \times 2\) 砖块。
    2. 两个水平的 \(1 \times 2\) 砖块。

    L 型砖块占 3 个单元,无法铺满 \(2 \times 2\) 的墙。所以 \(f(2) = 2\)

Python 代码实现

"""
设 f(n) 为铺满 2xN 墙壁的方案数。
推导出的递推关系为:f(n) = 2*f(n-1) + f(n-3)
边界条件:
f(0) = 1 (空墙壁只有一种方案)
f(1) = 1 (一个竖直的 1x2 砖块)
f(2) = 2 (两个竖直的 1x2 或 两个水平的 1x2)
"""
import sys
n = int(sys.stdin.readline())
dp = [1] * (n + 1)
dp[2], MOD = 2, 10000
for i in range(3, n + 1):
    dp[i] = (2 * dp[i - 1] + dp[i - 3]) % MOD
print(dp[n])
posted @ 2025-07-23 14:58  AFewMoon  阅读(16)  评论(0)    收藏  举报