【洛谷】P1990 覆盖墙壁

覆盖墙壁

题目描述

你有一个长为 N N N 宽为 2 2 2 的墙壁,给你两种砖头:一个长 2 2 2 1 1 1,另一个是 L 型覆盖 3 3 3 个单元的砖头。如下图:

0  0
0  00

砖头可以旋转,两种砖头可以无限制提供。你的任务是计算用这两种来覆盖 N × 2 N\times 2 N×2 的墙壁的覆盖方法。例如一个 2 × 3 2\times3 2×3 的墙可以有 5 5 5 种覆盖方法,如下:

012 002 011 001 011  
012 112 022 011 001

注意可以使用两种砖头混合起来覆盖,如 2 × 4 2\times4 2×4 的墙可以这样覆盖:

0112
0012

给定 N N N,要求计算 2 × N 2\times N 2×N 的墙壁的覆盖方法。由于结果很大,所以只要求输出最后 4 4 4 位。例如 2 × 13 2\times 13 2×13 的覆盖方法为 13465 13465 13465,只需输出 3465 3465 3465 即可。如果答案少于 4 4 4 位,就直接输出就可以,不用加前导 0 0 0,如 N = 3 N=3 N=3 时输出 5 5 5

输入格式

一个整数 N N N,表示墙壁的长。

输出格式

输出覆盖方法的最后 4 4 4 位,如果不足 4 4 4 位就输出整个答案。

解题思路

整体思路

显然,铺满长为n的墙壁的方案数和铺满前n-1的墙壁的方案数之间有相关性,所以这道题应该是一道递推问题。

那么不妨设f[n]为铺满长度为n的墙壁的方案数,我们需要考虑的是f[n]是由哪些状态转移来的。

f[n]的状态转移

f [ n ] = f [ n − 1 ] + f [ n − 2 ] + g [ n − 2 ] f[n] = f[n-1] + f[n-2] + g[n - 2] f[n]=f[n1]+f[n2]+g[n2]

状态转移1

显然f[n]可以由f[n-1]转移而来,在前n-1的长度的墙壁铺满的前提下在铺一个2X1的格子即可

状态转移2

显然f[n]可以由f[n-2]转移而来,但要注意,如果第n-1列竖着填充的话得到的状态与f[n-1]重复,因此填充方式应该是横向填充

状态转移3

分析完毕以上状态转移后,不难发现还有三角形的砖头没有使用,那么显然缺少状态没有分析。

不难发现,在砌墙壁的过程中,如果使用到了三角形的砖头,墙壁不一定会是正好完整的规则矩形,还有可能是在规则矩形的基础上凸出来一小块。

不妨设g[n]为前nX2的墙壁完整,第n+1列的墙壁只砌了一块(上下都有可能)
那么f[n]还可以由g[n-2]在加上一块三角形的砖头获得

g[n]的状态转移

g [ n ] = f [ n − 1 ] ∗ 2 + g [ n − 1 ] g[n] = f[n - 1] * 2 + g[n - 1] g[n]=f[n1]2+g[n1]

状态转移1

g[n]可以由规则的矩形转移的来,只需要在f[n-1]的基础上再任意添加一块三角形砖块即可。

状态转移2

g[n]可以由不规则的图形得来,只需要再g[n-1]中较短的那一边添加一块2X1的砖块即可。

AC代码

#include <cstdio>
#include <iostream>
#include <cstring>
#define endl '\n'
using namespace std;
const int N = 20;
const int mod = 10000;
int a[N]; // 第i行全部填满的方案数
int b[N]; // 第i行全部填满,第i+1行只填一个的方案数
/*
递推公式:
a[i] = a[i - 1] + a[i - 2] + b[i - 2];
b[i] = a[i - 1] * 2 + b[i - 1];
*/

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    a[1] = 1;
    a[2] = 2;
    b[1] = 2;
    b[2] = 4;
    int n;
    cin >> n;
    for (int i = 3; i <= n; i++)
    {
        a[i] = (a[i - 1] + a[i - 2] + b[i - 2]) % mod;
        b[i] = (a[i - 1] * 2 + b[i - 1]) % mod;
    }
    cout << a[n] % mod;
    return 0;
}
  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值