泥豪!我是2789617221guo!欢迎来|

2789617221guo

园龄:1个月粉丝:2关注:2

2025-02-19 20:16阅读: 7评论: 0推荐: 0

洛谷P1990 覆盖墙壁 题解

洛谷P1990 覆盖墙壁 题解

题目传送门

本题是一道非常好的递推题,请认真阅读,争取不看代码自己写出答案。

思路

我们可以设 \(f_i\) 为覆盖 \(2\times i\) 的所有覆盖方案。显然,边界条件 \(f_0\)(即没有列了,不用覆盖)和 \(f_1\)(只有 1 列,即一个 \(\text I\) 型砖块竖排)是为 1 的。可以根据最后几列的覆盖方法推导出递推式。

情况 1:1 个竖排 \(\text I\)

如图,这种情况下,可以根据 \(f_{i-1}\) 的方案数得来,前 \(i-1\) 列覆盖完毕后,只剩下 1 列,故只覆盖一个 \(\text I\) 型砖块。

情况 2:2 个横排 \(\text I\)

如图,这种情况下,类似情况 1,可以根据 \(f_{i-2}\) 的情况得来,前 \(i-2\) 列覆盖完毕后,忽略情况 1(因为已经计算过了),就只有这种情况了。

情况 3:1 个 \(\text L\)

如图,这种情况下,\(\text L\) 有一个凸起,这个凸起在上下 2 侧都有可能,所以最终的结果需要 \(\times 2\),要解决这种情况,需要考虑如下方法:

i:使用一个反向 \(\text L\) 补全缺口

如图,这种方法可以使用一个 \(\text L\) 补全凸起上方的缺口,此时已经覆盖好了 3 列,剩下的 \(i-3\) 列的方案数就是 \(f_{i-3}\) 了。

ii:使用一个横 \(\text I\) 解决缺口,再使用一个 \(\text L\) 补全新缺口

如图,这种方法使用了一个横 \(\text I\) 补全了旧缺口,却产生了一个新缺口,此时再使用一个新的 \(\text L\) 补全新缺口,剩下的 \(i-4\) 列的方案数为 \(f_{i-4}\)

iii iv v ... 所有的解法

我们发现,似乎可以使用更多的横向 \(I\) 不断地补全旧缺口,产生新缺口,再使用横向 \(\text I\),最后用一个 \(\text L\) 补全缺口就又是一种新的方法。我们可以发现,似乎这类方法的最后方案数可以是 \(f_{i-3},f_{i-4},f_{i-5},\dots ,f_{0}\),所以,只要我们把这些所有的方案数加起来,即 \(\sum_{i=0}^{i-3}{f_i}\),就可以了。

所以,在情况 3 下,总的方案数是 \(2\times \sum_{i=0}^{i-3}{f_i}\)

最终,我们成功推导出了 \(f_i\) 的递推式,即:

\[f_i=f_{i-1}+f_{i-2}+2\times \sum_{i=0}^{i-3}{f_i} \]

为了防止TLE,我们不难发现其中 \(\sum_{i=0}^{i-3}{f_i}\) 的部分是可以利用前缀和来优化的,定义 \(s\) 表示 \(f\) 的前缀和,即 \(s_i=\sum_{j=0}^{i}{f_j}\)

在调用 \(\sum_{i=0}^{i-3}{f_i}\) 时就可以直接调用 \(s_{i-3}\) 防止TLE了。

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int INF = 0x3f3f3f3f;
const double EPS = 1e-8;
const int N = 1e6 + 5;
const int MOD = 10000;
int n, s[N], f[N];
int main() {
cin >> n;
f[0] = s[0] = 1;
f[1] = 1;
s[1] = 2;
f[2] = 2;
s[2] = 4;
for(int i = 3; i <= n; i++) {
f[i] = (s[i - 1] + s[i - 3]) % MOD;
s[i] = (s[i - 1] + f[i]) % MOD;
}
cout << f[n] << endl;
return 0;
}

AC记录

AC,59ms,7.98MB


优化

我们其实可以通过上面的式子推出一个空间复杂度更好的递推式。

我们考虑

\[f_n=f_{n-1}+f_{n-2}+2\times \sum_{i=0}^{n-3}{f_i} \]

\[f_{n-1}=f_{n-2}+f_{n-3}+2\times \sum_{i=0}^{n-4}{f_i} \]

并且

\[f_n-f_{n-1}=f_{n-1}+f_{n-2}+2\times \sum_{i=0}^{n-3}{f_i}-f_{n-2}-f_{n-3}-2\times \sum_{i=0}^{n-4}{f_i} \]

化简后,得

\[f_n-f_{n-1}=f_{n-1}+f_{n-3} \]

移项,得最终递推式

\[f_n=2\times f_{n-1}+f_{n-3} \]

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int INF = 0x3f3f3f3f;
const double EPS = 1e-8;
const int N = 1e6 + 5;
const int MOD = 10000;
int n, f[N] = {1, 1, 2};
int main() {
cin >> n;
for(int i = 3; i <= n; i++) {
f[i] = (2 * f[i - 1] + f[i - 3]) % MOD;
}
cout << f[n] << endl;
return 0;
}

AC记录 2(优化后)

AC,50ms,4.22MB

本文作者:2789617221guo

本文链接:https://www.cnblogs.com/2789617221guo/p/18725150

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   2789617221guo  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起