写在前面🏅
蓝桥杯🏆2022年第十三届省赛真题-积木画
时间限制: 1Sec 内存限制: 256MB 提交: 623 解决: 135
题目描述
小明最近迷上了积木画,有这么两种类型的积木,分别为 I 型(大小为 2 个单位面积)和 L 型(大小为 3 个单位面积):
同时,小明有一块面积大小为 2 × N 的画布,画布由 2 × N 个 1 × 1 区域构成。小明需要用以上两种积木将画布拼满,他想知道总共有多少种不同的方式? 积木可以任意旋转,且画布的方向固定。
输入
输入一个整数 N,表示画布大小。
输出
输出一个整数表示答案。由于答案可能很大,所以输出其对 1000000007 取模后的值。
样例输入复制
3
样例输出复制
5
提示
五种情况如下图所示,颜色只是为了标识不同的积木:
对于所有测试用例,1 ≤ N ≤ 10000000.
解题思路1️⃣:
哎,但凡是比赛的时候再测一个数据也不会不过,太可惜了,但是写的时候思路是对的,可惜a[2][1]写错了。
思路:a[i][0]:i列积木的堆法,a[i][1]:i列多一块小方格的堆法。
如:
或者
不管这三块是怎么放的,都叫a[3][0].
如果在此基础上右边多一个小方格就叫a[3][1],注意小方格可以在第四列上一行也可以在第四列下一行(不好找图就不给了,自行想象)
给出动态规划方程:
a[i][0]=(a[i-2][0]+a[i-2][1]+a[i-1][0])%mod;
a[i][1]=(a[i-1][0]*2+a[i-1][1])%mod;
画布大小为i的排法,既a[i][0]的值:
- 先考虑少一块I型积木的排法,既a[i-1][0],这时加上一块I型积木就行了,
- 再考虑少一块L型积木的排法,既a[i-2][1],这时加上一块L型积木就行了,
- 考虑少两块I型积木的排法,既a[i-2][0],加上两块I型积木,注意,两块必需横着加进去,如果是竖着加,就相当于第一种类型排法了,重复了。
- 涉及缺更多积木时,会发现无论怎么排,排法都会和上述情况重复,也就是说,以上三种情况涵盖了a[i][0]的所有排法。
所以有:
a[i][0]=(a[i-2][0]+a[i-2][1]+a[i-1][0])%mod;
a[i][1]的排法,大家可以自行画图写出来。
写出初始状态:
a[1][0]=1,a[2][0]=2,a[1][1]=2,a[2][1]=4;
🌸给出完整代码:
#include<stdio.h>
#define mod 1000000007
long int a[10000001][2];
int main()
{
int n;
a[1][0]=1,a[2][0]=2,a[1][1]=2,a[2][1]=4;
scanf("%d",&n);
if(n==1)printf("1");
else if(n==2)printf("2");
else {
for(int i=3;i<=n;i++){
a[i][0]=(a[i-2][0]+a[i-2][1]+a[i-1][0])%mod;
a[i][1]=(a[i-1][0]*2+a[i-1][1])%mod;
}
printf("%ld",a[n][0]%mod);
}
return 0;
}
解体思路2️⃣:
首先我们直接来看三阶的,第一个和第二个我们可以发现I型积木拼放的方式是有2种的,或者看一和四都行,然后L型积木的拼接方式是1种看三和五(你把他们两个反转过来就是一种),那我们不妨想的简单一点所以递推公式就是:dp[i]=dp[i-1]*2+dp[i-3];
证明的方法就是我们刚才的思想过程,我们讲二维的矩阵看成了一维的,所以I型积木就是等于1个方格,所以我们记为i-1,L型积木就是等于1.5个方格,但是L型积木不能单独出现,必须成双的出现,所以我们记为i-3,又由于I型积木出现在一个位置有两种方式,所以我们乘以二,L型积木出现只有一直方式我们乘以1,就结束了。
但是我们还要进行初始化前三个:
当i等于1的时候dp就是1,这个没啥说的,只能放一种I型不管咋放都一样.
当i等于2的时候dp是2,因为可以放两个I型,可以水平放可以竖直放2种.
当i等于3的时候就是题目当中的情况dp等于5,
💐参考代码:
#include<stdio.h>
#include<string.h>
#define mod 1000000007
int dp[10000005];
int main()
{
int n;
scanf("%d",&n);
memset(dp,0,sizeof(dp));
dp[1]=1,dp[2]=2,dp[3]=5;
for(int i=4;i<=n;i++)
{
dp[i]=(dp[i-1]*2%mod+dp[i-3]%mod)%mod;
}
printf("%d\n",dp[n]);
return 0;
}
解题思路3️⃣:
状态转移方程
-
情况一:单独使用 I 型积木拼接, d p [ i ] + = d p [ i − 1 ] dp[i] += dp[i-1] dp[i]+=dp[i−1]
-
情况二:使用两个 I 型积木拼接, d p [ i ] + = d p [ i − 2 ] dp[i]+=dp[i-2] dp[i]+=dp[i−2]
-
情况三:使用两个 L 型积木拼接, d p [ i ] + = 2 ⋅ d p [ i − 3 ] dp[i]+=2\cdot dp[i-3] dp[i]+=2⋅dp[i−3]
-
情况四:情况四只有 i > = 4 i>=4 i>=4 时才可能出现,具体讨论如下:
-
若 i = = 4 i4 i4 ,只存在长度为 4 的拼接情况,假设 d p [ 0 ] = 1 dp[0]=1 dp[0]=1,也就是说 d p [ 4 ] + = d p [ 0 ] ⋅ 2 dp[4]+=dp[0]\cdot 2 dp[4]+=dp[0]⋅2
-
若 i = = 5 i5 i5,存在长度为 4 , 5 4,5 4,5 的拼接情况,即 d p [ 5 ] + = ( d p [ 0 ] + d p [ 1 ] ) ⋅ 2 dp[5] += (dp[0]+dp[1])\cdot 2 dp[5]+=(dp[0]+dp[1])⋅2
-
若 i = = 6 i 6 i6,继续推导有: d p [ 6 ] + = ( d p [ 0 ] + d p [ 1 ] + d p [ 2 ] ) ⋅ 2 dp[6]+=(dp[0]+dp[1]+dp[2])\cdot 2 dp[6]+=(dp[0]+dp[1]+dp[2])⋅2
-
若 i = = 7 i7 i7,推导有: d p [ 7 ] + = ( d p [ 0 ] + d p [ 1 ] + d p [ 2 ] + d p [ 3 ] ) ⋅ 2 dp[7]+=(dp[0]+dp[1]+dp[2]+dp[3])\cdot 2 dp[7]+=(dp[0]+dp[1]+dp[2]+dp[3])⋅2
按照上述推导,不难发现 d p [ i ] + = ( d p [ 0 , 1 , 2 , . . . , i − 4 ] ) ⋅ 2 dp[i]+=(dp[0,1,2,…,i-4])\cdot 2 dp[i]+=(dp[0,1,2,…,i−4])⋅2,因此可以定义一个变量 s u m sum sum 存储 d p [ 0 , 1 , 2 , . . i ] dp[0,1,2,…i] dp[0,1,2,…i] 的值,在 i i i 增大的同时更新 s u m sum sum 的值,初始情况 s u m = 0 sum=0 sum=0。
返回结果
最终 d p [ N ] dp[N] dp[N] 就是题目所求值,这道题就这样解决了。
🌷 代码编写
#include <iostream>
#include <math.h>
#define ll long long
// #include <bits/stdc++.h>
using namespace std;
const int MOD = 1000000007;
int main() {
ll n, a1, a2, a3;
a1 = 5;
a2 = 2;
a3 = 1;
cin >> n;
ll sum = 0;
for (ll i = 4; i <= n; ++i) {
ll val = 0;
val += a1;
val += a2;
val += (a3 * 2L);
if (i >= 4) {
val += sum * 2 + 2;
sum += a3;
}
val %= MOD;
a3 = a2;
a2 = a1;
a1 = val;
}
cout << a1;
return 0;
}
写在最后🧐
如果有哪里看不懂,可以评论区或者私信我,
如果觉得对你有用,就给本蒟蒻一个好评吧。