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;
}