Luogu P5303 [GXOI/GZOI2019] 逼死强迫症

Solution

\(f_i\) 表示长度为 \(i\) 的路的答案。

当不存在 \(1\times1\) 的方块时,有明显的性质是一次放方块的操作只能是放一个竖块或放两个横块。

所以只有 \(f_{i-1}\)\(f_{i-2}\) 对考虑到的 \(f_i\) 有贡献。那么这时的 \(f\) 就是一个斐波那契数列,即 \(f_i=f_{i-1}+f_{i-2}\)

容易发现,两个 \(1\times1\) 距离确定的方块的贡献为 \(2\)

考虑枚举两个 \(1\times1\) 方块之间的距离以及第一个 \(1\times1\) 方块的位置:

\[\begin{aligned} \mathrm{Ans} &=\sum_{i=3}^n\sum_{j=1}^{n-i+1}2\times f_{j-1}f_{n-j-i+1}\\ &=2\times \sum_{i=0}^{n-3}\sum_{j=0}^{n-i-3}f_{j}f_{n-j-i-3}\\ &=2\times \sum_{i=0}^{n-3}{f_i\sum_{j=0}^{n-i-3}f_j} \end{aligned}\]

注意到这是需要求出斐波那契数列的前缀和。

而对于斐波那契数列,有恒等式:$$\sum_{i=0}^n f_i=f_{n+2}-1$$

化简得:

\[\begin{aligned} \mathrm{Ans} &=2\times \sum_{i=0}^{n-3}f_i(f_{n-i-1}-1)\\ &=2\times(\sum_{i=0}^{n-3}f_i f_{n-i-1} - \sum_{i=0}^{n-3} f_i)\\ &=2\times(\sum_{i=0}^{n-3}f_i f_{n-i-1} - f_{n-1} +1)\\ \end{aligned}\]

此时我们令 \(\mathrm{sum}_n =\sum_{i=0}^n f_i f_{n-i}\)

继续化简得:

\[\begin{aligned} \mathrm{Ans} &=2\times(\sum_{i=0}^{(n-1)-2}f_i f_{(n-1)-i} - f_{n-1} +1)\\ &=2\times(\mathrm{sum}_{n-1} - 2f_{n-1} -f_{n-2}+1)\\ \end{aligned}\]

现在我们考虑求出 \(\mathrm{sum}_n\) 的递推式,并使用矩阵快速幂优化:

\[\begin{aligned} \mathrm{sum}_n &=\sum_{i=0}^n f_i f_{n-i}\\ &=f_n+\sum_{i=0}^{n-1}f_i(f_{n-i-1}+f_{n-i-2})\\ &=f_n+\sum_{i=0}^{n-1}f_i f_{n-i-1}+\sum_{i=0}^{n-1}f_i f_{n-i-2}\\ &=f_n+\sum_{i=0}^{n-1}f_i f_{n-i-1}+\sum_{i=0}^{n-2}f_i f_{n-i-2}\\ &=f_n+\mathrm{sum}_{n-1}+\mathrm{sum}_{n-2}\\ \end{aligned}\]

由此我们可以得出转移矩阵:

\(\begin{bmatrix}\mathrm{sum}_{n-1}& \mathrm{sum}_{n-2} &f_{n-1} &f_{n-2}\end{bmatrix} \times \begin{bmatrix}1&1&0&0\\1&0&0&0\\1&0&1&1\\1&0&1&0\end{bmatrix}=\begin{bmatrix}\mathrm{sum}_{n}& \mathrm{sum}_{n-1} &f_{n} &f_{n-1}\end{bmatrix}\)

Code

/* ChongYun */
#include<bits/stdc++.h>
#define int long long
using namespace std;
int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<1)+(x<<3)+ch-'0';
		ch=getchar();
	}
	return x*f;
}
const int mod=1e9+7;
int q,n;
struct Matrix{
    int A[4][4];
    void clear(){ memset(A,0,sizeof(A)); }
    void init(){ clear(),A[0][0]=A[1][1]=A[2][2]=A[3][3]=1; }
    Matrix operator * (const Matrix &qwq)const{
        Matrix now; now.clear();
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                for(int k=0;k<4;k++){
                    now.A[i][j]=(now.A[i][j]+A[i][k]*qwq.A[k][j]%mod)%mod;
                }
            }
        }
        return now;
    }
}Rhy,Mil;
void init(){
    Rhy.clear();
    Rhy.A[0][0]=Rhy.A[1][0]=Rhy.A[2][0]=Rhy.A[3][0]=1;
    Rhy.A[0][1]=1,Rhy.A[2][2]=Rhy.A[3][2]=1,Rhy.A[2][3]=1;
    Mil.clear();
    Mil.A[0][0]=2,Mil.A[0][1]=Mil.A[0][2]=Mil.A[0][3]=1;
    return ;
}
Matrix qpow(Matrix a,int b){
    Matrix qans; qans.init();
    while(b){
        if(b&1) qans=qans*a;
        a=a*a;
        b>>=1;
    }
    return qans;
}
signed main(){
    init(),q=read();
    while(q--){
        n=read();
        if(n<=2){
            printf("0\n");
            continue;
        }
        Matrix qwq=qpow(Rhy,n-2);
        Matrix now; now.clear();
        for(int i=0;i<1;i++){
            for(int j=0;j<4;j++){
                for(int k=0;k<4;k++){
                    now.A[i][j]=(now.A[i][j]+Mil.A[i][k]*qwq.A[k][j]%mod)%mod;
                }
            }
        }
        printf("%lld\n",(2*(now.A[0][0]%mod-2*now.A[0][2]%mod-now.A[0][3]%mod+1)%mod+mod)%mod);
    }
    return 0;
}
posted @ 2025-02-07 17:29  HAM_qwq  阅读(26)  评论(5编辑  收藏  举报