P8784 [蓝桥杯 2022 省 B] 积木画 题解
题目传送门
1.分析:
这道题是一道 dp 题,
我们可以这样想,一个积木放上去后,可能会出现三种情况:第一行比第二行多出一个积木;两行积木数相等;第二行比第一行多出一个积木。
这时候有同学可能会问:为什么最多就多出一个积木呢?
因为最后的答案一定是两行积木数相等,如果两行差的多了,就不能用 L 型积木填补。只用 I 型积木填补的话,只能横着填补,我们完全可以在之前相差不超过
所以,状态定义就是:int f[10000005][3]。注意:这里的 f[i][0] 和 f[i][2] 表示更长的一列的长度为
接下来就是动态转移方程了。
如果第一行比第二行多出一个积木,也就是状态 f[i][0]。此时我们可以用一个 I 型积木在第一行横向填补,这样在填补前第二行就会多出一个积木,也就是 f[i-1][2];也可以用一个 L 型积木填补第 f[i-2][1]。
如果第二行比第一行多出一个积木,也就是状态 f[i][2]。此时与上一种情况类似,也是两种方案,分别是用一个 I 型积木在第二行横向填补和用一个 L 型积木进行填补。分别是 f[i-1][0] 和 f[i-2][1]。
最后,也是最复杂的一种情况,就是两行积木数相等,即状态 f[i][1]。此时有 f[i-2][1];可以用一个 I 型积木纵向填补第 f[i-1][1];可以用一个 L 型积木填补第 f[i-1][2];还可以用一个 L 型积木填补第 f[i-1][0]。
温馨提示:这一部分可能不是很好懂,同学们可以画个图帮助理解。
初始化就很简单了,即一列都没有,两行积木数都为 f[0][1]=1。
输出也很简单,就是前
2.AC 代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,f[10000005][3];
int main(){
cin>>n;
f[0][1]=1;
for(int i=1;i<=n;i++){
f[i][0]=(f[i-2][1]+f[i-1][2])%mod;
f[i][1]=((f[i-2][1]+f[i-1][1])%mod+(f[i-1][0]+f[i-1][2])%mod)%mod;//两两相加就取模,防止超出int
f[i][2]=(f[i-2][1]+f[i-1][0])%mod;
}
cout<<f[n][1];
return 0;
}