POJ 3420

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/84201218

这道题非常综合,和上一道题很类似,这道题,也是铺地砖问题,

只不过 地面变成了 4*n 同时需要输入 mod ,结果对 mod 取模。。

那么有了上一题的经验。

我们开始整理一下 b [ n ] 代表 4*n 的不可分割矩阵种类个数。。。

首先 b[ 1 ] = 1 ,

b [ 2 ] = 4 ,之后我们发现了一个类似的规律,我们所谓之不可分割矩阵,要求的就是每一行之间都存在一个连接的木板。。,同行之间是无所谓的,但是不同行之间都需要一块木板进行连接,才能保证 这两行合在了一起,成了不可分割的一部分

我们简单的画一下,发现 n >=  3  之后 有了一定的规律, 每个不可分割的模板花纹看上去都几乎一样,(这里可以自己画一下看看)

然后神奇的事情出现了,我们发现了这样一个规律:(n >= 3) 

b [ n ] = 2 (n 为奇数 ) ;

 b [ n ] = 3 (n为偶数) ;

那么  a [ n ] = a [ n - 1 ] * b [ 1 ] + a [ n - 2 ] * b [ 2 ] ....... + a [ 0 ] * b [ n ];

但是如果这样还不够简便,我们可以退出 a [ n - 1 ] 表达式

a [ n - 1 ] = a [ n - 2 ] * b [ 1 ] + ....... a [ 0 ] * b [ n - 1 ]

然后 a [ n - 1 ] 带回 同时 把 b [ n ] 具体数字代入

 a [ n ] = 5 * a [ n - 2 ] + 6 * a [ n - 3 ] + 5 * ( a [ n - 4 ] + a [ n - 5 ] ....... a [ 0 ] )

但是这样的话,,后边还会存在一堆数字, 这道题 n <= 1e9 所以这样跑下去还是不够快速

由上式 我们还可以 推出

a [ n - 1 ] = 5 * a [ n - 3 ] + 6 * a [ n - 4 ] ........

那么我们惊讶的发现,如果两式相减,我们可以消去一大部分累赘的式子

那么就可知

 a [ n ]  =  a [ n - 1 ] + 5 * a [ n - 2 ] + a [ n - 3 ] - a [ n - 4 ];

有了这个式子,我们就很好处理了,但是依旧避免不了需要 一个循环跑一次,还是不够优秀

那么 我们脑洞大开,联想一下之前那个巨大数据范围的斐波那契数列

如果这里我们用一下之前学过的矩阵来优化 不就可以更加便捷了吗  ?

那么开始构造矩阵, 基础矩阵的话

就是  \begin{bmatrix} An-4 \\ An-3 \\ An-2 \\ An-1 \end{bmatrix} 而我们构造的矩阵不就是 \begin{bmatrix} 0 & 1 & 0 & 0\\ 0& 0&1 &0 \\ 0& 0& 0& 1\\ -1& 1& 5 & 1 \end{bmatrix} 就会推出\begin{bmatrix} An-3 \\ An-2 \\ An-1 \\ An \end{bmatrix}

所以最终 输出 A [ 3 ] [ 0 ] 就好了

以下是矩阵的模板 可以使用一下,可以自己设置行和列

struct Matrix
{
    int n,m;
    int a[MAXN][MAXM];
    void clears()
    {
        n=m=0;
        memset(a,0,sizeof(a));
    }
    Matrix operator *(const Matrix &b)
    {
        Matrix tmp;
        tmp.clears();
        tmp.n=n;
        tmp.m=b.m;
        for(int i=0; i<n; ++i)
            for(int j=0; j<b.m; j++)
                for(int k=0; k<m; k++)
                {
                    tmp.a[i][j] += a[i][k]*b.a[k][j];
                    tmp.a[i][j] %= mod;
                }
        return tmp;
    }

};

还有矩阵快速幂的模板

Matrix pow_(Matrix t,int x)
{
        Matrix E;
        E.clears();
        E.n=E.m=t.n;
        for(int i=0; i<t.n; i++)
        {
            E.a[i][i]=1;
        }
        if(x==0)return E;
        while(x)
        {
            if(x&1)
                E = E * t;
            t = t * t;
            x >>= 1;
        }
        return E;
}

有了这些模板,我们套用一下 就可以解决这个问题了。。。

(矩阵快速幂可以帮我们把正常的加法递推运算优化)

以下为 AC 代码

#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=10;
const int MAXM=10;

int r,mod;

struct Matrix
{
    int n,m;
    int a[MAXN][MAXM];
    void clears()
    {
        n=m=0;
        memset(a,0,sizeof(a));
    }
    Matrix operator *(const Matrix &b)
    {
        Matrix tmp;
        tmp.clears();
        tmp.n=n;
        tmp.m=b.m;
        for(int i=0; i<n; ++i)
            for(int j=0; j<b.m; j++)
                for(int k=0; k<m; k++)
                {
                    tmp.a[i][j] += a[i][k]*b.a[k][j];
                    tmp.a[i][j] %= mod;
                }
        return tmp;
    }

};
Matrix pow_(Matrix t,int x)
{
        Matrix E;
        E.clears();
        E.n=E.m=t.n;
        for(int i=0; i<t.n; i++)
        {
            E.a[i][i]=1;
        }
        if(x==0)return E;
        while(x)
        {
            if(x&1)
                E = E * t;
            t = t * t;
            x >>= 1;
        }
        return E;
}
int main()
{
    while(~scanf("%d %d",&r,&mod)&&r&&mod)
    {
        int a[]= {1,1,5,11};
        if(r<=3)
        {
            printf("%d\n",a[r]%mod);
            continue;
        }
        Matrix A;
        A.clears();
        A.n=A.m=4;
        A.a[0][1]=A.a[1][2]=A.a[2][3]=1;

        A.a[3][0]=-1; A.a[3][1]=1; A.a[3][2]=5; A.a[3][3]=1;

        Matrix temp;
        temp = pow_(A, r-3);
        Matrix x;
        x.clears();
        x.n=4;
        x.m=1;
        x.a[0][0]=1;
        x.a[1][0]=1;
        x.a[2][0]=5;
        x.a[3][0]=11;
        x = temp*x;
        printf("%d\n",(x.a[3][0]+mod)%mod);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40924940/article/details/84201218
POJ