背景:
好像也没什么。
题目传送门:
题意:
给一个
2
∗
n
2*n
2∗n的矩阵,现在要用
2
∗
(
n
−
1
)
2*(n-1)
2∗(n−1)的矩形和
2
2
2块
1
∗
1
1*1
1∗1的正方形铺满这个矩阵,要求这两个正方形不能相邻(边不能靠在一起)。
思路 1 1 1:
显然要用
d
p
dp
dp。
设
f
i
,
j
f_{i,j}
fi,j表示在前
i
i
i列已经用了
j
j
j块
1
∗
1
1*1
1∗1的正方形的方案。
我们知道若没有这两块正方形,其方案数是
Fibonacci
\text{Fibonacci}
Fibonacci数列。
用类似的思想。
f
i
,
0
=
f
i
−
1
,
0
+
f
i
−
2
,
0
f_{i,0}=f_{i-1,0}+f_{i-2,0}
fi,0=fi−1,0+fi−2,0。
f
i
,
1
=
f
i
−
1
,
1
+
2
∗
f
i
−
1
,
0
f_{i,1}=f_{i-1,1}+2*f_{i-1,0}
fi,1=fi−1,1+2∗fi−1,0。
f
i
,
2
=
f
i
−
2
,
1
+
f
i
−
1
,
2
+
f
i
−
2
,
2
f_{i,2}=f_{i-2,1}+f_{i-1,2}+f_{i-2,2}
fi,2=fi−2,1+fi−1,2+fi−2,2。
解释一下:
[
1
]
[1]
[1]:由于没有没有这两块正方形,其方案数是
Fibonacci
\text{Fibonacci}
Fibonacci数列。
[
2
]
[2]
[2]:用了一块正方形,因此有两种情况:
1.
\ \ \ \ \ \ \ 1.
1.在原来的列就用了,因此方案数为
f
i
−
1
,
1
f_{i-1,1}
fi−1,1。
2.
\ \ \ \ \ \ \ 2.
2.在当前仅剩的一个这一列用,那么前面肯定
i
−
1
i-1
i−1列没有用过,那么当前第
i
i
i列可以放在上面或下面,即
2
2
2种可能,因此方案数为
2
∗
f
i
−
1
,
0
2*f_{i-1,0}
2∗fi−1,0。
[
3
]
[3]
[3]:用了两块正方形,因此有两种情况:
1.
\ \ \ \ \ \ \ 1.
1.在原来的列就用了,也就早就铺满了,剩下的肯定就是类似
Fibonacci
\text{Fibonacci}
Fibonacci数列的东西了,因此方案数为
f
i
−
1
,
2
+
f
i
−
2
,
2
f_{i-1,2}+f_{i-2,2}
fi−1,2+fi−2,2。
2.
\ \ \ \ \ \ \ 2.
2.在当前第
i
i
i列用,那么可以发现放置方法是固定的,不会产生新的贡献,直接继承
f
i
−
2
,
1
f_{i-2,1}
fi−2,1(不会出现两个正方形在相邻两列的情况)即可。(可以自己在草稿纸上画画。)
最后矩阵乘法优化即可。
思路 2 2 2:
发现上面的式子用矩阵乘法真的不好做。
因此探求一种更优秀的做法。
f
i
=
f
i
−
1
+
f
i
−
2
+
2
∗
∑
j
=
1
i
−
3
f
i
b
j
f_i=f_{i-1}+f_{i-2}+2*\sum_{j=1}^{i-3}fib_j
fi=fi−1+fi−2+2∗∑j=1i−3fibj
其中
f
i
b
j
fib_j
fibj表示
Fibonacci
\text{Fibonacci}
Fibonacci数列第
j
j
j项。
为什么可以这样呢?
对于思路
1
1
1来说,由于我们只用求
f
i
,
2
f_{i,2}
fi,2,因此可以将
[
1
]
,
[
2
]
[1],[2]
[1],[2]带入
[
3
]
[3]
[3]中,化简即可得到上面的式子。
那么
∑
\sum
∑怎么消除呢?
Fibonacci
\text{Fibonacci}
Fibonacci数列有一个性质:
∑
j
=
1
i
−
3
f
i
b
j
=
f
i
b
i
−
1
−
1
\sum_{j=1}^{i-3}fib_{j}=fib_{i-1}-1
∑j=1i−3fibj=fibi−1−1,因此有:
f
i
=
f
i
−
1
+
f
i
−
2
+
2
∗
(
f
i
b
i
−
1
−
1
)
f_i=f_{i-1}+f_{i-2}+2*(fib_{i-1}-1)
fi=fi−1+fi−2+2∗(fibi−1−1)
f
i
=
f
i
−
1
+
f
i
−
2
+
2
f
i
b
i
−
1
−
2
f_i=f_{i-1}+f_{i-2}+2fib_{i-1}-2
fi=fi−1+fi−2+2fibi−1−2
好像好了许多。
矩阵乘法如下:
[
f
i
f
i
−
1
f
i
b
i
−
1
f
i
b
i
−
2
−
2
]
∗
[
1
1
2
2
1
1
0
0
0
0
0
0
1
1
0
0
0
1
0
0
0
0
0
0
1
]
=
[
f
i
+
1
f
i
f
i
b
i
f
i
b
i
−
1
−
2
]
\left[ \begin{matrix} f_{i}\\ f_{i-1}\\ fib_{i-1}\\ fib_{i-2}\\ -2 \end{matrix} \right]*\left[ \begin{matrix} 1&1&2&2&1\\ 1&0&0&0&0\\ 0&0&1&1&0\\ 0&0&1&0&0\\ 0&0&0&0&1 \end{matrix} \right]= \left[ \begin{matrix} f_{i+1}\\ f_{i}\\ fib_{i}\\ fib_{i-1}\\ -2 \end{matrix} \right]
⎣⎢⎢⎢⎢⎡fifi−1fibi−1fibi−2−2⎦⎥⎥⎥⎥⎤∗⎣⎢⎢⎢⎢⎡1100010000201102010010001⎦⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎡fi+1fifibifibi−1−2⎦⎥⎥⎥⎥⎤
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 1000000007
#define LL long long
using namespace std;
struct node
{
LL a[5][5];
node clear()
{
memset(a,0,sizeof(a));
}
friend node operator * (const node a,const node b)
{
node c;
c.clear();
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
for(int k=0;k<5;k++)
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%mod)%mod;
return c;
}
} base,ans;
int n;
LL work(int x)
{
base.a[0][0]=1,base.a[0][1]=1,base.a[0][2]=2,base.a[0][3]=2,base.a[0][4]=1;
base.a[1][0]=1,base.a[1][1]=0,base.a[1][2]=0,base.a[1][3]=0,base.a[1][4]=0;
base.a[2][0]=0,base.a[2][1]=0,base.a[2][2]=1,base.a[2][3]=1,base.a[2][4]=0;
base.a[3][0]=0,base.a[3][1]=0,base.a[3][2]=1,base.a[3][3]=0,base.a[3][4]=0;
base.a[4][0]=0,base.a[4][1]=0,base.a[4][2]=0,base.a[4][3]=0,base.a[4][4]=1;
ans.clear();
for(int i=0;i<5;i++)
ans.a[i][i]=1;
while(x)
{
if(x&1) ans=ans*base;
base=base*base;
x>>=1;
}
return ((ans.a[1][2]+ans.a[1][3])%mod-ans.a[1][4]*2%mod+mod)%mod;
}
int main()
{
int T,x;
scanf("%d",&T);
while(T--)
{
scanf("%d",&x);
printf("%lld\n",work(x-1));
}
}