题目大意
给出一个 2 ∗ n ( 1 ≤ n ≤ 1 e 6 ) 2*n(1 \leq n \leq 1e6) 2∗n(1≤n≤1e6)的墙壁,规定只能用两种可以任意旋转的砖头覆盖,砖头的形状如下:
求使用这两种砖头覆盖墙壁的方案数对 10000 10000 10000取模的结果。
解题思路
这种题目主要是推出递推式,虽然是二维的,但是定义状态时仍可以定义 f [ i ] f[i] f[i]表示填充满前面的 2 ∗ i 2*i 2∗i个格子的方案数,假设当前要填第 i i i列,那么可以尝试一些放置方法,然后从前面已经得出的答案中递推求出:
- 假设竖着放置 1 ∗ 2 1*2 1∗2的砖块在第 i i i列,那么 f [ i ] + = f [ i − 1 ] f[i] += f[i - 1] f[i]+=f[i−1]
- 假设最后两列横着放两个 1 ∗ 2 1*2 1∗2的砖块,那么 f [ i ] + = f [ i − 2 ] f[i] += f[i - 2] f[i]+=f[i−2]
- 假设最后放置一个丁字砖块(这个砖块有两种放置方法,因此最后这个累加的答案乘二),此时会得到一个凸出,为了消除这个凸出,可以再放置一个丁字块,这时 f [ i ] + = f [ i − 3 ] f[i] += f[i - 3] f[i]+=f[i−3];还可以先放一个 1 ∗ 2 1*2 1∗2,然后再放置一个丁字块,这时 f [ i ] + = f [ i − 4 ] f[i] += f[i - 4] f[i]+=f[i−4];仔细观察,还可以上下交错放两个 1 ∗ 2 1*2 1∗2,然后放一个丁字块补齐凸出,这时 f [ i ] + = f [ i − 5 ] f[i] += f[i - 5] f[i]+=f[i−5]…以此类推可以发现,这种放置方式最终能放置的方案总数为 ∑ 0 i − 3 f [ i ] \sum_{0}^{i - 3}f[i] ∑0i−3f[i]
综上, f [ i ] = f [ i − 1 ] + f [ i − 2 ] + 2 ∗ ∑ 0 i − 3 f [ i ] f[i] = f[i - 1] + f[i - 2] + 2*\sum_{0}^{i - 3} f[i] f[i]=f[i−1]+f[i−2]+2∗∑0i−3f[i],初始化为 f [ 0 ] = 1 , f [ 1 ] = 1 , f [ 2 ] = 2 f[0] = 1, f[1] = 1, f[2] = 2 f[0]=1,f[1]=1,f[2]=2。
reference:https://www.luogu.com.cn/blog/222223/solution-p1990
#include <bits/stdc++.h>
using namespace std;
#define ENDL "\n"
typedef pair<int, int> pii;
typedef long long ll;
const int Mod = 10000;
const int maxn = 1e6 + 10;
ll f[maxn], sum[maxn];
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
f[0] = 1, f[1] = 1, f[2] = 2;
sum[0] = 1, sum[1] = 2, sum[2] = 4;
for (int i = 3; i <= n; i++) {
f[i] = (f[i] + f[i - 1]) % Mod;
f[i] = (f[i] + f[i - 2]) % Mod;
f[i] = (f[i] + sum[i - 3] * 2) % Mod;
sum[i] = (sum[i - 1] + f[i]) % Mod;
}
cout << f[n] << endl;
return 0;
}