洛谷 P1990 覆盖墙壁(DP/递推)

传送门


题目大意

给出一个 2 ∗ n ( 1 ≤ n ≤ 1 e 6 ) 2*n(1 \leq n \leq 1e6) 2n(1n1e6)的墙壁,规定只能用两种可以任意旋转的砖头覆盖,砖头的形状如下:

在这里插入图片描述

求使用这两种砖头覆盖墙壁的方案数对 10000 10000 10000取模的结果。

解题思路

这种题目主要是推出递推式,虽然是二维的,但是定义状态时仍可以定义 f [ i ] f[i] f[i]表示填充满前面的 2 ∗ i 2*i 2i个格子的方案数,假设当前要填第 i i i列,那么可以尝试一些放置方法,然后从前面已经得出的答案中递推求出:

  • 假设竖着放置 1 ∗ 2 1*2 12的砖块在第 i i i列,那么 f [ i ] + = f [ i − 1 ] f[i] += f[i - 1] f[i]+=f[i1]
  • 假设最后两列横着放两个 1 ∗ 2 1*2 12的砖块,那么 f [ i ] + = f [ i − 2 ] f[i] += f[i - 2] f[i]+=f[i2]
  • 假设最后放置一个丁字砖块(这个砖块有两种放置方法,因此最后这个累加的答案乘二),此时会得到一个凸出,为了消除这个凸出,可以再放置一个丁字块,这时 f [ i ] + = f [ i − 3 ] f[i] += f[i - 3] f[i]+=f[i3];还可以先放一个 1 ∗ 2 1*2 12,然后再放置一个丁字块,这时 f [ i ] + = f [ i − 4 ] f[i] += f[i - 4] f[i]+=f[i4];仔细观察,还可以上下交错放两个 1 ∗ 2 1*2 12,然后放一个丁字块补齐凸出,这时 f [ i ] + = f [ i − 5 ] f[i] += f[i - 5] f[i]+=f[i5]…以此类推可以发现,这种放置方式最终能放置的方案总数为 ∑ 0 i − 3 f [ i ] \sum_{0}^{i - 3}f[i] 0i3f[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[i1]+f[i2]+20i3f[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;
}

猜你喜欢

转载自blog.csdn.net/qq_44691917/article/details/116423322