luogu P5303 [GXOI/GZOI2019]逼死强迫症
只有两行,考虑递推,设\(f_i\)为没有那两个\(1*1\)的,前\(i\)列的方案,可以发现一次可以放一个竖的或两个横的,也就是\(f_i=f_{i-1}+f_{i-2}\)
再设\(g_i\)表示有那两个\(1*1\)的,前\(i\)列的方案,首先和\(f\)类似,可以放一个竖的或两个横的\(1*2\),然后\(1*1\)可以放出长度为奇数,\(\ge3\)的两种矩形,或者长度为偶数,\(\ge4\)的两种矩形,所以$$g_i=g_{i-1}+g_{i-2}+(2\sum_{j=3}^{i-j\ge 0} [j\mod 2=1]f_{i-j})+(2\sum_{j=4}^{i-j\ge 0} [j\mod 2=0]f_{i-j})$$
然后可以发现\(\sum_{j=3}^{i-j\ge 0} [j\mod 2=1]f_{i-j}=f_{i-2}-1\),\(\sum_{j=4}^{i-j\ge 0} [j\mod 2=0]f_{i-j}=f_{i-3}\),所以$$g_i=g_{i-1}+g_{i-2}+2(f_{i-2}-1)+2f_{i-3}$$
注意\(n\)很大,要使用矩乘优化
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define db double
using namespace std;
const int mod=1e9+7;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
struct matrix
{
int a[6][6];
matrix(){memset(a,0,sizeof(a));}
void inii(){for(int i=0;i<6;++i) a[i][i]=1;}
matrix operator * (const matrix &bb) const
{
matrix an;
for(int i=0;i<6;++i)
for(int j=0;j<6;++j)
{
LL nw=0;
for(int k=0;k<6;++k) nw+=1ll*a[i][k]*bb.a[k][j];
an.a[i][j]=nw%mod;
}
return an;
}
matrix operator ^ (const LL &bb) const
{
matrix an,a=*this;
an.inii();
LL b=bb;
while(b)
{
if(b&1) an=an*a;
a=a*a,b>>=1;
}
return an;
}
}aa,bb;
int main()
{
aa.a[0][0]=aa.a[0][1]=1,aa.a[0][5]=mod-1;
bb.a[0][0]=bb.a[1][0]=bb.a[0][1]=bb.a[1][2]=1;
bb.a[3][3]=bb.a[4][3]=bb.a[3][4]=bb.a[5][5]=1;
bb.a[1][3]=bb.a[2][3]=2,bb.a[5][3]=2;
int T=rd();
while(T--) printf("%d\n",(aa*(bb^(rd()-1))).a[0][3]);
return 0;
}