[题解] P10975 Mondriaan's Dream / 蒙德里安的梦想
xingchen666 · · 题解
状态压缩 dp 模板题,但是题解区没看到
对于每一行的状态的枚举,我们把第 0,1,2 三个数字的其中一个表示。这里定义:
0表示该格子是横放矩形的一格1表示该格子是竖向矩形的上面一格2表示该格子是竖向矩形的下面一格
这时候每行的状态可以由一个
可以发现,如果一个格子值为 2 ,那么它上面的格子就必须为 1;反之,上面的格子一定不能为 1。对当前行的状态,找到上一行所有满足该条件的状态的值全部加起来就行了。
这里不需要枚举,我们可以提前计算并存起来。定义 1。
可以使用滚动数组省去一点点空间。时间复杂度
::::success[Code]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read() {
ll res = 0, neg = 1; char ch = getchar();
while(ch<'0' or ch>'9') { if(ch == '-') neg = -1; ch = getchar(); }
while(ch>='0' and ch<='9') res = res*10 + ch-'0', ch = getchar();
return res * neg;
}
void write(ll x) {
if(x < 0) putchar('-'), x = -x;
if(x < 10) putchar(x+'0');
else write(x/10), putchar(x%10+'0');
}
const int N = 20;
int n,m;
int a[N];
ll sum[2][2500];
int main() {
while(true) {
n = read(), m = read();
if(!n and !m) break ;
if(m > n) swap(n,m);
int sttcnt = 1;
for(int i=1; i<=m; i++) sttcnt *= 3;
ll ans = 0;
for(int i=1, op=0; i<=n; i++, op^=1) {
for(int stt2=0; stt2<(1<<m); stt2++) {
sum[op^1][stt2] = 0;
if(i == 1) sum[op][stt2] = 0;
}
if(i == 1) sum[op][0] = 1;
for(int stt=0; stt<sttcnt; stt++) {
int stt2 = 0, stt3 = 0;
bool is_inlaw = true; int cnt0 = 0;
for(int j=1, tmp=stt; j<=m; j++, tmp/=3) {
a[j] = tmp%3;
if(a[j] == 0) cnt0++;
else {
if(cnt0&1) {
is_inlaw = false;
break;
}
cnt0 = 0;
}
if(a[j] == 2) stt2 |= (1<<(j-1));
if(a[j] == 1) stt3 |= (1<<(j-1));
}
if(cnt0&1) is_inlaw = false;
if(!is_inlaw) continue ;
ll res = sum[op][stt2];
sum[op^1][stt3] += res;
if(i == n and stt3 == 0) ans += res;
}
}
write(ans), putchar('\n');
}
return 0;
}
::::