题目传送门luogu
题目传送门loj
题目描述
ITX351 要铺一条
2
×
N
2 \times N
2×N的路,为此他购买了 N块
2
×
1
2 \times 1
2×1的方砖。可是其中一块砖在运送的过程中从中间裂开了,变成了两块
1
×
1
1 \times 1
1×1的砖块!
ITX351 由此产生了一个邪恶的想法:他想要在这条路上故意把两块
1
×
1
1 \times 1
1×1的砖块分开铺,不让两块砖有相邻的边,其他砖块可以随意铺,直到整条路铺满。这样一定可以逼死自身强迫症 sea5!
也许下面的剧情你已经猜到了——他为此兴奋不已,以至于无法敲键盘。于是,他请你帮忙计算一下,有多少种方案可以让自己的阴谋得逞。
输入格式
每个测试点包含多组数据,输入文件的第一行是一个正整数 T,表示数据的组数。注意各组数据之间是独立无关的。
接下来 T 行,每行包含一个正整数 N,代表一组数据中路的长度。
输出格式
输出应包含 T行,对于每组数据,输出一个正整数,表示满足条件的方案数。
由于答案可能非常的大,你只需要输出答案对 1000000007 (
1
0
9
10^{9}
109 + 7) 取模后的结果。
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
简洁题意
多组数据
(
T
≤
500
)
(T≤500)
(T≤500),用
2
×
1
2 \times 1
2×1 的方砖铺路,其中一块断裂成
2
2
2 块
1
×
1
1×1
1×1 的正方形方砖,求满
2
×
N
(
N
≤
2
×
1
0
9
)
2 \times N (N≤2×10^9)
2×N(N≤2×109)的道路 且
2
2
2 块正方形方砖不相邻的方案数。
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
解题报告
一、观察下列方块
假如我往左边偏,另一块 1 × 1 1×1 1×1 只能在左边,故此我们得出一条重要性质:
两块 1 × 1 1×1 1×1 的正方形方砖一定是对角的,且形成一个完整的“含方块整体”,且这种整体对于每一长度只有2种。
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
二、考虑旁边
旁边的显然就是没有 1 × 1 1×1 1×1方块的普通铺路法
那么,令 f ( i ) f(i) f(i) 表示 铺 规模为 2 × i 2 \times i 2×i 的路的方案数
那么有
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \ \ \ \\ \ \\ \\ \ \\ \ \ \ } f ( i ) = f ( i − 1 ) + f ( i − 2 ) f(i)=f(i-1)+f(i-2) f(i)=f(i−1)+f(i−2)
f ( i − 1 ) f(i-1) f(i−1)铺上一个竖块, f ( i − 2 ) f(i-2) f(i−2) 铺上 2 2 2 个横块
其中 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
嗯,斐波那契
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
三、转移
接下来似乎很难转移
因为这种“含方块整体”的长度不定,且左右两边长度不定
考虑终极目的
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ } A n s ( i ) Ans(i) Ans(i)表示 按要求填满 2 × N 2 \times N 2×N道路的方案数
拆成几种好计算的,能覆盖所有情况的
一般就是分为有和没有
有的人是最后一列是否有方块格
跟我最后一列是否有“含方块整体”差不多
都是为了利用到斐波那契的前缀和
那么有
g [ i ] [ 0 ] g[i][0] g[i][0]表示 在满足“含方块整体”不在最后一列时 填满 2 × N 2 \times N 2×N道路的方案数
g [ i ] [ 1 ] g[i][1] g[i][1]表示 在满足“含方块整体”在最后一列时 填满 2 × N 2 \times N 2×N道路的方案数
\text{ \ \ \ \ \ \ \\ \ \ \ \ \ \ \ \ \\ \ \ \ \ \ \ \ \\ \ \ \ } 显然有 A n s ( i ) = g [ i ] [ 0 ] + g [ i ] [ 1 ] Ans(i)=g[i][0]+g[i][1] Ans(i)=g[i][0]+g[i][1]
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
考虑转移:
g [ i ] [ 0 ] = A n s ( i − 1 ) + A n s ( i − 2 ) g[i][0]=Ans(i-1)+Ans(i-2) g[i][0]=Ans(i−1)+Ans(i−2)
g [ i ] [ 1 ] = 2 × ∑ j = 0 i − 3 f ( j ) g[i][1]=2\times \sum_{j=0}^{i-3}{f(j)} g[i][1]=2×∑j=0i−3f(j)
枚举普通铺法的规模 0 0 0 ~ i − 3 i-3 i−3 (下图黄色部分) ;
其中 × 2 \times 2 ×2的原因是 各长度"含方块整体”有2种
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
\text{ \ \ \\ \\ \\ \ \ \ \ \ \ \ \ \\ \ \ \ }
h ( x ) h(x) h(x)表示斐波那契数列前 x x x 项前缀和,那么有 h ( x ) = ∑ j = 0 x − 1 f ( j ) = f ( x + 2 ) − 1 h(x)=\sum_{j=0}^{x-1}{f(j)}=f(x+2)-1 h(x)=∑j=0x−1f(j)=f(x+2)−1
注意到我这里的斐波那契虽然是从下标0开始的,但是性质是不变的 ; 后者是斐波那契的性质,读者请自行查询
g [ i ] [ 1 ] = 2 × h ( i − 3 ) = 2 × [ f ( i − 1 ) − 1 ] g[i][1]=2\times h(i-3)=2 \times[ f(i-1)-1] g[i][1]=2×h(i−3)=2×[f(i−1)−1]
\text{ \ \ \ \ \ } 得到 A n s ( i ) = A n s ( i − 1 ) + A n s ( i − 2 ) + 2 × f ( i − 1 ) − 2 Ans(i)=Ans(i-1)+Ans(i-2)+2 \times f(i-1)-2 Ans(i)=Ans(i−1)+Ans(i−2)+2×f(i−1)−2
题目做到这里,可以打一个50分暴力, O ( n T ) O(nT) O(nT)
\text{ \ \ \ \ \ \ \ \ \ \ \ }
\text{ \ \ \ \ \ \ \ \ \ \ \ }
四、矩阵乘法优化
⎡
1
1
2
0
−
2
⎢
⎡
A
n
s
(
i
−
1
)
⎢
⎡
A
n
s
(
i
)
⎢
⎡ \text{ \ \ } 1\text{ \ \ } 1\text{ \ \ } 2\text{ \ \ } 0\text{ } -2 ⎢\text{ \ \ \ \ \ \ \ \ \ \ \ } ⎡Ans(i-1)⎢ \text{ \ \ \ \ \ \ \ \ \ \ \ } ⎡ \text{ \ \ }Ans(i)\text{ \ \ } ⎢
⎡ 1 1 2 0 −2⎢ ⎡Ans(i−1)⎢ ⎡ Ans(i) ⎢
⎢
1
0
0
0
0
⎢
⎢
A
n
s
(
i
−
2
)
⎢
⎢
A
n
s
(
i
−
1
)
⎢
⎢\text{ \ \ } 1\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } ⎢ \text{ \ \ \ \ \ \ \ \ \ \ \ } ⎢ Ans(i-2)⎢ \text{ \ \ \ \ \ \ \ \ \ \ \ } ⎢Ans(i-1) ⎢
⎢ 1 0 0 0 0 ⎢ ⎢Ans(i−2)⎢ ⎢Ans(i−1)⎢
⎢
0
0
1
1
0
⎢
×
⎢
f
(
i
−
1
)
⎢
=
⎢
f
(
i
)
⎢
⎢\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 1\text{ \ \ } 1\text{ \ \ } 0\text{ \ \ } ⎢\text{ \ \\ \ }\times \text{ \ \ \ } ⎢\text{ \ } f(i-1)\text{ \ } ⎢ \text{ \ \\ \ }= \text{ \ \ } ⎢\text{ \ \ \ \ } f(i)\text{ \ \ \ \ \ } ⎢
⎢ 0 0 1 1 0 ⎢ × ⎢ f(i−1) ⎢ = ⎢ f(i) ⎢
⎢
0
0
1
0
0
⎢
⎢
f
(
i
−
2
)
⎢
⎢
f
(
i
−
1
)
⎢
⎢ \text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 1\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } ⎢\text{ \ \ \ \ \ \ \ \ \ \ \ } ⎢\text{ \ } f(i-2)\text{ \ }⎢ \text{ \ \ \ \ \ \ \ \ \ \ \ } ⎢\text{ \ } f(i-1)\text{ \ \ } ⎢
⎢ 0 0 1 0 0 ⎢ ⎢ f(i−2) ⎢ ⎢ f(i−1) ⎢
⎡
0
0
0
0
1
⎢
⎣
1
⎦
⎢
1
⎦
⎡ \text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 1\text{ \ \ } ⎢\text{ \ \ \ \ \ \ \ \ \ \ } ⎣\text{ \ \\ \ \ \ \ \ \ } 1\text{ \ \ \ \ \ \ } ⎦ \text{ \ \ \ \ \ \ \ \ \ \ \ } ⎢\text{ \ \\ \ \ \ \ } 1\text{ \ \ \ \\ \ \ } ⎦
⎡ 0 0 0 0 1 ⎢ ⎣ 1 ⎦ ⎢ 1 ⎦.
目标矩阵的 m a [ i ] [ j ] ma[i][j] ma[i][j]一般认为 由左边的矩阵第 i i i行与右边矩阵第 j j j列对应相乘 再相加
矩阵快速幂 时间复杂度 O ( 5 3 T log n ) O(5^3T\log n) O(53Tlogn)
初始矩阵(可以不一样):
⎡
A
n
s
(
1
)
=
0
⎢
⎡Ans(1)=0⎢ \text{ \ \ \ \ \ \ \ \ \ \ \ }
⎡Ans(1)=0⎢
⎢
A
n
s
(
0
)
=
0
⎢
⎢Ans(0)=0⎢ \text{ \ \ \ \ \ \ \ \ \ \ \ }
⎢Ans(0)=0⎢
⎢
f
(
1
)
=
1
⎢
⎢\text{ \ } f(1)=1\text{ \ } ⎢\text{ \ \\ \ }
⎢ f(1)=1 ⎢
⎢
f
(
0
)
=
1
⎢
⎢\text{ \ } f(0)=1\text{ \ } ⎢\text{ \ \ \ \ \ \ \ \ \ \ \ }
⎢ f(0)=1 ⎢
⎣
1
⎦
⎣\text{ \ \\ \ \ \ \ \ \ } 1\text{ \ \ \ \ \ \ \ } ⎦
⎣ 1 ⎦
\text{ \ \ \ \ \ \ \ }
任一矩阵同 对角线为1,其余为0的矩阵 相乘等于自己
感性理解: m a [ i ] [ j ] ma[i][j] ma[i][j]只能由原来的那一行 乘上一个除了第 j j j个之外都为0的列
⎡
1
0
0
0
0
⎢
⎡ \text{ \ \ } 1\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 0 \text{\ \ }⎢
⎡ 1 0 0 0 0 ⎢
⎢
0
1
0
0
0
⎢
⎢\text{ \ \ } 0\text{ \ \ } 1\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } ⎢
⎢ 0 1 0 0 0 ⎢
⎢
0
0
1
0
0
⎢
⎢\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 1\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } ⎢
⎢ 0 0 1 0 0 ⎢
⎢
0
0
0
1
0
⎢
⎢ \text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 1\text{ \ \ } 0\text{ \ \ } ⎢
⎢ 0 0 0 1 0 ⎢
⎡
0
0
0
0
1
⎢
⎡ \text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 0\text{ \ \ } 1\text{ \ \ } ⎢
⎡ 0 0 0 0 1 ⎢.
五、上代码:
#include<cstdio>
#include<cstring>
#define LL long long
const LL mod=1e9+7;
struct mat{
LL a[10][10];
mat(LL t=0){
memset(a,0,sizeof(a));
a[1][1]=a[2][2]=a[3][3]=a[4][4]=a[5][5]=t;
}
mat operator * (const mat &B){
mat C;
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
for(int k=1;k<=5;k++)
C.a[i][j]=(C.a[i][j]+a[i][k]*B.a[k][j]+mod)%mod;
return C;
}
}ma,st(0);
void init()
{
st.a[1][1]=st.a[2][1]=0; st.a[3][1]=st.a[4][1]=st.a[5][1]=1;
ma.a[1][1]=1 ,ma.a[1][2]=1 ,ma.a[1][3]=2 ,ma.a[1][4]=0 ,ma.a[1][5]=-2;
ma.a[2][1]=1 ,ma.a[2][2]=0 ,ma.a[2][3]=0 ,ma.a[2][4]=0 ,ma.a[2][5]=0;
ma.a[3][1]=0 ,ma.a[3][2]=0 ,ma.a[3][3]=1 ,ma.a[3][4]=1 ,ma.a[3][5]=0;
ma.a[4][1]=0 ,ma.a[4][2]=0 ,ma.a[4][3]=1 ,ma.a[4][4]=0 ,ma.a[4][5]=0;
ma.a[5][1]=0 ,ma.a[5][2]=0 ,ma.a[5][3]=0 ,ma.a[5][4]=0 ,ma.a[5][5]=1;
/* 1 1 2 0 -2
1 0 0 0 0
0 0 1 1 0
0 0 1 0 0
0 0 0 0 1*/
}
void ksm(LL p)
{
mat b=ma,ans(1);
while(p>0){
if(p%2==1) ans=ans*b;
b=b*b;p>>=1;
}/*
for(int i=1;i<=5;i++,printf("\n"))
for(int j=1;j<=5;j++) printf("%lld ",ans.a[i][j]);*/
ans=ans*st;
printf("%lld\n",ans.a[1][1]);
}
int main()
{
int T;LL n;init();
scanf("%d",&T);
while(T--){
scanf("%lld",&n);
ksm(n-1);
}
return 0;
}