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}+(2sum_{j=3}^{i-jge 0} [jmod 2=1]f_{i-j})+(2sum_{j=4}^{i-jge 0} [jmod 2=0]f_{i-j})$$

然后可以发现(sum_{j=3}^{i-jge 0} [jmod 2=1]f_{i-j}=f_{i-2}-1),(sum_{j=4}^{i-jge 0} [jmod 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
",(aa*(bb^(rd()-1))).a[0][3]);
    return 0;
}
原文地址:https://www.cnblogs.com/smyjr/p/10763306.html