开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 31 天,点击查看活动详情
题目描述
小明最近迷上了积木画,有这么两种类型的积木,分别为 I 型(大小为 22 个单位面积)和 L 型(大小为 33 个单位面积):
同时,小明有一块面积大小为 的画布,画布由 个 区域构成。
小明需要用以上两种积木将画布拼满,他想知道总共有多少种不同的方式?
积木可以任意旋转,且画布的方向固定。
输入格式
输入一个整数 ,表示画布大小。
输出格式
输出一个整数表示答案。
由于答案可能很大,所以输出其对 1000000007 取模后的值。
数据范围
。
输入样例:
3
输出样例:
5
样例解释
五种情况如下图所示,颜色只是为了标识不同的积木:
题目分析
本题参考思路来自 Amonologue的题解。
由于本题行数为2,状态转移的方案并不多,所以可以采取线性DP的思想枚举。
定义 表示前 列被填满,且向 列伸出的状态所占据方格的数目为 的方案数。
此处的状态以二进制表示,可知可以为 00,01,10,11 四种,分别对应 为 0,1,1,2。
当 j=0 时可知第 列可为一个竖条或由第 列伸出的两个横条,即 f[i][0] = f[i-1][0] + f[i-1][2] 。
当 j=1 时可知第 列可为沿 轴翻转的两种 或由第 列伸出的一个方格再加上第 列的一个横条。
当 j=2 时可知第 列为开始放置的两个横条或由第 列伸出的一个方格再加上第 列的一个 。
初始化第一层的状态,最终复杂度为 。
Accept代码
#include <bits/stdc++.h>
using namespace std;
const int mod = 1000000007;
int n;
long long f[2][3]; // f[i][j] 表示前 i 列已经填满且对地 i+1 列的方块伸出数量
int main()
{
cin >> n;
f[1][0] = 1;
f[1][1] = 2;
f[1][2] = 1;
for (int i = 2; i <= n; i ++)
{
f[i & 1][0] = (f[i - 1 & 1][0] + f[i - 1 & 1][2]) % mod;
f[i & 1][1] = (f[i - 1 & 1][0] * 2 + f[i - 1 & 1][1]) % mod;
f[i & 1][2] = (f[i - 1 & 1][0] + f[i - 1 & 1][1]) % mod;
}
cout << f[n & 1][0];
return 0;
}