> 文章列表 > E - 积木画(状态压缩DP)

E - 积木画(状态压缩DP)

E - 积木画(状态压缩DP)

E - 积木画(状态压缩DP)

1、问题

E - 积木画

2、分析

这道题很明显是一道DP题,而且是一个简化版的状态压缩DP。

(1)状态表示

f[i][j]f[i][j]f[i][j]表示前面i−1i-1i1已经摆好,并且第iii列的状态是jjj的条件下,所有的摆法数量。·
为什么这里是i−1i-1i1呢,请看下面的讲解。

(2)状态转移

在状态转移之前,我们先看如下规定:
E - 积木画(状态压缩DP)

很明显,f[i][j]f[i][j]f[i][j]f[i+1][j]f[i+1][j]f[i+1][j]是两个截然不同的状态,那么当我们在第iii列放积木的时候,由于积木形状的特殊性,我们不难发现,第iii列放的积木会影响到第i+1i+1i+1列的状态,而正是这种影响在两个截然不同的状态之间搭建起了一个桥梁,即实现了状态的转移,因此我们接下来的讨论就是根据第iii列的不同的积木的摆法,去写转移方程。

在讲解之前,我们需要给各个状态做一下标记:
详细地状态规定如下图所示:
E - 积木画(状态压缩DP)
现在开始直接讨论iiii+1i + 1i+1列的两种状态。

我们去枚举第iii列的所有状态,黑色表示iii列自带的状态,红色和橙色表示我们在第iii列所有能填的情况。所有的情况如下图所示:
E - 积木画(状态压缩DP)

将上图转化为状态转移方程:
f[i+1][0]=f[i][0]+f[i][3]f[i+1][1]=f[i][0]+f[i][2]f[i+1][2]=f[i][0]+f[i][1]f[i+1][3]=f[i][0]+f[i][1]+f[i][2]+f[i][3]f[i+1][0]=f[i][0]+f[i][3] \\\\f[i+1][1]=f[i][0]+f[i][2] \\\\f[i+1][2]=f[i][0]+f[i][1] \\\\f[i+1][3]=f[i][0]+f[i][1]+f[i][2]+f[i][3] f[i+1][0]=f[i][0]+f[i][3]f[i+1][1]=f[i][0]+f[i][2]f[i+1][2]=f[i][0]+f[i][1]f[i+1][3]=f[i][0]+f[i][1]+f[i][2]+f[i][3]

(3)初末状态

初始状态的话,我们只需要让f[1][0]=1f[1][0] = 1f[1][0]=1即可。即我们在第111列没有积木填充的方案数是111。为什么呢?
因为当前列的状态是由前一列的积木的放置状况决定的,而第000列不存在,所以没法放积木,所以第111列的状态只有000是合法的。
末状态即(f[n][3]+f[n][0])(f[n][3] +f[n][0])(f[n][3]+f[n][0])或者写作f[n+1][0]f[n+1][0]f[n+1][0]

这里解释一下为什么前面要写成f[n][3]+f[n][0]f[n][3]+f[n][0]f[n][3]+f[n][0]
因为如果第iii列是空的,所以我们可以自动填充一个竖着的积木即可。

(4)滚动数组优化

由于这道题的数据范围很大,我们的DP数组可能存不下,而我们发现我们每次存储都只用到了上一层的数据,对于上一层之前的数据其实是没有用的,也就是说我们只需要在两层之间不断地迭代滚动即可,无需开这么大的空间。
那么滚动的方法即我们将下标和1取&\\&&运算即可。

3、代码

#include<bits/stdc++.h>
#define endl '\\n'
#define INF 0x3f3f3f3f
#define int long long 
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
int f[3][4];void solve()
{int n;cin >> n;f[1][0] = 1;for(int i = 1; i <= n; i ++ ){f[i + 1 & 1][0] = (f[i & 1][0] + f[i & 1][3]) % mod;f[i + 1 & 1][1] = (f[i & 1][0] + f[i & 1][2]) % mod;f[i + 1 & 1][2] = (f[i & 1][0] + f[i & 1][1]) % mod;f[i + 1 & 1][3] = (f[i & 1][0] + f[i & 1][1] + f[i & 1][2]) % mod;}cout << f[n + 1 & 1][0] << endl;
}
signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);solve();
}