蓝桥杯2022年第十三届省赛真题-积木画
时间限制: 1Sec1Sec1Sec 内存限制: 256MB256MB256MB
题目描述:
小明最近迷上了积木画,有这么两种类型的积木,分别为 I 型(大小为 2 个单位面积)和 L 型(大小为 3 个单位面积):

同时,小明有一块面积大小为 2 × N 的画布,画布由 2 × N 个 1 × 1 区域构成。小明需要用以上两种积木将画布拼满,他想知道总共有多少种不同的方式? 积木可以任意旋转,且画布的方向固定。
输入
输入一个整数 N,表示画布大小。
输出
输出一个整数表示答案。由于答案可能很大,所以输出其对 100000000710000000071000000007 取模后的值。
样例输入
3
样例输出
5
提示
五种情况如下图所示,颜色只是为了标识不同的积木:

对于所有测试用例,1≤N≤100000001 ≤ N ≤ 100000001≤N≤10000000
思路:
动态规划
dpi,1dp_{i,1}dpi,1为长度为iii的积木以第一种状态结尾的方案数

dpi,3dp_{i,3}dpi,3为长度为iii的积木以第二种状态结尾的方案数

dpi,3dp_{i,3}dpi,3为长度为iii的积木以第三种状态结尾的方案数

状态转移dpi,3dp_{i,3}dpi,3
状态三最后两个都是填满的,那么最后一块有四种可能
最后一块放III

那么对应的就是dpi−1,3dp_{i-1,3}dpi−1,3
最后一块放两条横的

对应状态就是dpi−2,3dp_{i-2,3}dpi−2,3
最后一块放反LLL型的

前面需要一个凸出的来接收,对应状态就是dpi−1,1dp_{i-1,1}dpi−1,1
最后一块放LLL型的

对应状态转移就是dpi−1,2dp_{i-1,2}dpi−1,2
所以转移方程为
dpi,3=dpi−1,3+dpi−1,2+dpi−1,1+dpi−2,3
dp_{i,3}=dp_{i-1,3}+dp_{i-1,2}+dp_{i-1,1}+dp_{i-2,3}
dpi,3=dpi−1,3+dpi−1,2+dpi−1,1+dpi−2,3
状态转移dpi,2dp_{i,2}dpi,2
最后一个上面放一条横的

对应状态就是dpi−1,1dp_{i-1,1}dpi−1,1
最后一个放反L

对应状态就是dpi−2,3dp_{i-2,3}dpi−2,3
所以dpi,2dp_{i,2}dpi,2的转移方程为
dpi,2=dpi−1,1+dpi−2,3
dp_{i,2}=dp_{i-1,1}+dp_{i-2,3}
dpi,2=dpi−1,1+dpi−2,3
状态转移dpi,1dp_{i,1}dpi,1
最后一个下面放横的

对应状态就是dpi−1,2dp_{i-1,2}dpi−1,2
最后一个放反LLL

对应状态就是dpi−2,3dp_{i-2,3}dpi−2,3
那么dpi,1dp_{i,1}dpi,1的转移方程为
dpi,1=dpi−1,2+dpi−2,3
dp_{i,1}=dp_{i-1,2}+dp_{i-2,3}
dpi,1=dpi−1,2+dpi−2,3
那么所有的转移方程都推出来了
dpi,1=dpi−1,2+dpi−2,3dpi,2=dpi−1,1+dpi−2,3dpi,3=dpi−1,1+dpi−1,2+dpi−1,3+dpi−2,3
dp_{i,1}=dp_{i-1,2}+dp_{i-2,3}\\
dp_{i,2}=dp_{i-1,1}+dp_{i-2,3}\\
dp_{i,3}=dp_{i-1,1}+dp_{i-1,2}+dp_{i-1,3}+dp_{i-2,3}
dpi,1=dpi−1,2+dpi−2,3dpi,2=dpi−1,1+dpi−2,3dpi,3=dpi−1,1+dpi−1,2+dpi−1,3+dpi−2,3
题目给的NNN的数据范围为1≤N≤100000001 ≤ N ≤ 100000001≤N≤10000000
显然我们开不了这么大的数组
观察转移方程可以发现,我们需要的最多只是dpi−2dp_{i-2}dpi−2的值,也就是我们一次最多只需要维护dpi−2,dpi−1,dpidp_{i-2},dp_{i-1},dp_{i}dpi−2,dpi−1,dpi这三个值
所以我们开个3∗43*43∗4的数组滚动迭代即可
循环开始之前先预处理dp1,dp2dp_1,dp_2dp1,dp2的值
每加一次对1e9+71e9+71e9+7取余一次
最后dpn%3,3dp_{n\%3,3}dpn%3,3就是最终答案
代码:
#include <bits/stdc++.h>
#define ll long long
const ll MAX = 1e9 + 7;
using namespace std;
ll dp[3][4] = { 0 };
int n;
int main() {
cin >> n;
dp[1][3] = 1;
dp[2][1] = 1;
dp[2][2] = 1;
dp[2][3] = 2;
for (int i = 3; i <= n; i++) {
dp[i % 3][3] = (dp[(i - 1) % 3][3] + dp[(i - 2) % 3][3] + dp[(i - 1) % 3][1] + dp[(i - 1) % 3][2]) % MAX;
dp[i % 3][2] = (dp[(i - 1) % 3][1] + dp[(i - 2) % 3][3]) % MAX;
dp[i % 3][1] = (dp[(i - 1) % 3][2] + dp[(i - 2) % 3][3]) % MAX;
}
cout << dp[n % 3][3];
return 0;
}

1040

被折叠的 条评论
为什么被折叠?



