peiwenjun's blog 没有知识的荒原

P5303 [GXOI/GZOI2019]逼死强迫症 题解

题目描述

\(T\) 组询问,用 \(2\)\(1\times 1\) 的方块和 \(n-1\)\(1\times 2\) 的方块(可以旋转)铺满 \(2\times n\) 的格子,要求这 \(2\)\(1\times 1\) 的方块没有公共边,求方案数,对 \(10^9+7\) 取模。

数据范围

  • \(1\le T\le 500,1\le n\le 2\cdot 10^9\)

时间限制 \(\texttt{1s}\) ,空间限制 \(\texttt{500MB}\)

分析

如果只用 \(1\times 2\) 的砖块来铺 \(2\times n\) 的网格,考虑最后一列怎么填,可以得到递推式 \(f_n=f_{n-1}+f_{n-2}\) ,又因为初始值\(f_0=f_1=1\),所以答案就是斐波那契数列。

如果 \(2\)\(1\times 1\) 的砖不在同一行,不妨分别在左上和右下。

那么这 \(2\) 列及其之间的列的填法唯一,又因为中间列数为奇数且至少有 \(3\) 列,所以方案数为 \(\sum_{i+j\le n-3,i+j\not\equiv n\pmod 2}f_if_j\)

如果 \(2\)\(1\times 1\) 的砖在同一行,不妨都在第一行。

那么这 \(2\) 列及其之间的列填法也唯一,又因为中间列数为偶数且至少有 \(4\) 列,所以方案数为 \(\sum_{i+j\le n-4,i+j\equiv n\pmod 2}f_if_j\)

加在一起,刚好考虑了所有 \(i+j\le n-3\) 的有序对 \((i,j)\)

别忘了上面两个不妨,因此答案为 \(2\sum\limits_{i+j\le n-3}f_if_j\)

至此可以做到 \(\mathcal O(Tn)\) ,期望得分 \(50pts\)


斐波那契数列, \(2\cdot 10^9\) 的数据范围,很难不联想到矩阵快速幂,目标变为构建常系数线性递推关系。

\(h_n=\sum\limits_{i+j\le n}f_if_j\) ,则 \(h_n=h_{n-1}+\sum_{i=0}^nf_if_{n-i}\)

\(g_n=\sum_{i=0}^nf_if_{n-i}\) ,规定 \(f_{-1}=0\) ,则:

\[\begin{aligned} g_n&=f_n+\sum_{i=1}^nf_if_{n-i}\\ &=f_n+\sum_{i=1}^n(f_{i-1}+f_{i-2})f_{n-i}\\ &=f_n+g_{n-1}+g_{n-2}\\ \end{aligned} \]

写成矩阵乘法形式:

\[\begin{bmatrix} f_{n-2}&f_{n-1}&g_{n-2}&g_{n-1}&h_{n-1}\\ \end{bmatrix} \times \begin{bmatrix} 0&1&0&1&1\\ 1&1&0&1&1\\ 0&0&0&1&1\\ 0&0&1&1&1\\ 0&0&0&0&1\\ \end{bmatrix} = \begin{bmatrix} f_{n-1}&f_n&g_{n-1}&g_n&h_n\\ \end{bmatrix}\\ \]

时间复杂度 \(\mathcal O(T\cdot 5^3\log m)\)

#include<bits/stdc++.h>
#define vec array<int,5>
#define mat array<vec,5>
using namespace std;
const int mod=1e9+7;
int n,t;
mat operator*(mat a,mat b)
{
    mat c={};
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++)
            for(int k=0;k<5;k++)
                c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j])%mod;
    return c;
}
int main()
{
    for(scanf("%d",&t);t--;)
    {
        scanf("%d",&n);
        if(n<=2) printf("0\n");
        else if(n==3) printf("2\n");
        else
        {
            mat a={vec{0,1,0,1,1},vec{1,1,0,1,1},vec{0,0,0,1,1},vec{0,0,1,1,1},vec{0,0,0,0,1}};
            mat res={vec{1,1,1,2,3},{},{},{},{}};///[f_0,f_1,g_0,g_1,h_1]
            for(int k=n-4;k;a=a*a,k>>=1) if(k&1) res=res*a;
            printf("%d\n",2*res[0][4]%mod);
        }
    }
    return 0;
}

posted on 2022-04-05 17:39  peiwenjun  阅读(7)  评论(0)    收藏  举报

导航