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;
}
posted @ 2019-04-24 16:52  ✡smy✡  阅读(174)  评论(0编辑  收藏  举报