平铺方案
题目链接:ybt高效进阶1-1-5
题目大意
用 1 × 2 1\times2 1×2 和 2 × 2 2\times2 2×2 的方块铺满 2 × n 2\times n 2×n 的矩阵,问你有多少种方案。
思路
那我们可以想,要通过怎样的排列方式,才会形成
2
×
x
2\times x
2×x 的矩阵。
(这个矩阵要是最小最基础的,然后把很多个这些矩阵拼在一起,就可以得到
2
×
n
2\times n
2×n 的矩阵)
可以想到这样几种:
- 直接摆一个 2 × 2 2\times 2 2×2 的。
- 摆 1 × 2 1\times 2 1×2 的,横着摆两个
- 摆 1 × 2 1\times 2 1×2 的,竖着摆一个。
那第一第二种就是可以使宽度
+
2
+2
+2,而第三种可以使宽度
+
1
+1
+1。
或者说,要得到
f
n
f_n
fn,有两种方案是变成求
f
n
−
2
f_{n-2}
fn−2 的,而有一种方案是求
f
n
−
1
f_{n-1}
fn−1 的。
你会发现这就是 dp, f i = f i − 1 + 2 × f i − 2 f_{i}=f_{i-1}+2\times f_{i-2} fi=fi−1+2×fi−2。
不过从样例都可以看出要用高精。
为了减少代码量,可以把
2
×
f
i
−
2
2\times f_{i-2}
2×fi−2 变成
f
i
−
2
+
f
i
−
2
f_{i-2}+f_{i-2}
fi−2+fi−2,就只用弄高精加的了。
代码
#include<cstdio>
#include<iostream>
#define mo 100000
using namespace std;
struct gj {
int n, a[51];
}f[260], re;
int n, tmp;
gj operator +(gj x, gj y) {//高精加
re.n = max(x.n, y.n);
re.a[0] = 0;
for (int i = 0; i < re.n; i++) {
re.a[i] += x.a[i] + y.a[i];
re.a[i + 1] = re.a[i] / mo;
re.a[i] %= mo;
}
if (re.a[re.n] != 0) re.n++;
return re;
}
int main() {
f[1].n = 1;
f[1].a[0] = 1;
f[2].n = 1;
f[2].a[0] = 3;
for (int i = 3; i <= 250; i++) {
f[i] = f[i - 1] + f[i - 2] + f[i - 2];
}
while (scanf("%d", &n) != EOF) {
printf("%d", f[n].a[f[n].n - 1]);
for (int i = f[n].n - 2; i >= 0; i--) {
tmp = mo / 10;
while (!(f[n].a[i] / tmp)) {
printf("0");
tmp /= 10;
}
printf("%d", f[n].a[i]);
}
printf("\n");
}
return 0;
}