poj3420

描述:

首先,这道题是poj2663的升级版https://blog.youkuaiyun.com/q_t_pang/article/details/81077519

在一个4*n的棋盘上,用1*2的多米诺骨牌来平铺,问铺满的方法有多少种。

同样的,我们将棋盘分为左右两部分,右边部分是不可分割的。

1、当右边部分是4*1时,不可分割的只有一种铺满方法

2、当右边部分是4*2时,不可分割的有四种平铺方法

3、当右边部分是4*3时,不可分割的有两种平铺方法

4、当右边部分是4*4时,不可分割的有3种平铺方法

当往下继续推倒时发现,当n为奇数且n>=3时,不可分割的平铺方法为2;当n为偶数且n>=4时,不可分割的平铺方法为3;

所以,f(n)=f(n-1)*b(1)+f(n-2)*b(2)+f(n-3)*b(3)+f(n-4)*b(4)+…+f(0)*b(n)

即f(n)=f(n-1)+f(n-2)*4+f(n-3)*2+f(n-4)*3+…+f(0)*b(n)

 

下面求解上述表达式

f(n-1)=f(n-2)+f(n-3)*4+f(n-4)*2+f(n-5)*3+…+f(0)*b(n-1)

上述两个表达式相加可得

f(n)=5*f(n-2)+6*f(n-3)+5*(f(n-4)+f(n-5)+…+f(0))

所以f(n-1)=5*f(n-3)+6*f(n-4)+5*(f(n-5)+f(n-6)+…+f(0))

上述两个表达式相减可得

f(n)-f(n-1)=5*f(n-2)+f(n-3)-f(n-4)

所以最终可得f(n)=f(n-1)+5*f(n-2)+f(n-3)-f(n-4)

 

但由于本题所给范围很大,我们需要用矩阵快速幂的方法节省时间

矩阵求解上述问题的方法详述

a[n-3]    0 1 0 0       a[n-4]

a[n-2] = 0 0 1 0   *  a[n-3]

a[n-1]    0 0 0 1      a[n-2]
a[n]       -1 1 5 1     a[n-1]

另中间的矩阵为T,初始(a[0] a[1] a[2] a[3])为A

那么A=T(r-3)次幂 * A(注意:矩阵乘法没有交换率

求T的n次幂时采用矩阵快速幂的方法

 

#include<iostream>
#include<string.h>
using namespace std;
const int MAXN=10;
const int MAXM=10;
int r,mod;
//矩阵类模板
struct Matrix{
    int n,m;
    int a[MAXN][MAXM];
    void clear(){
        n=m=0;
        memset(a,0,sizeof(a));
    }
    Matrix operator +(const Matrix &b) const {
        Matrix tmp;
        tmp.n=n;tmp.m=m;
        for (int i=0;i<n;++i)
            for(int j=0;j<m;++j)
                tmp.a[i][j]=a[i][j]+b.a[i][j];
        return tmp;
    }
    Matrix operator -(const Matrix &b)const{
        Matrix tmp;
        tmp.n=n;tmp.m=m;
        for (int i=0;i<n;++i)
            for(int j=0;j<m;++j)
                tmp.a[i][j]=a[i][j]-b.a[i][j];
        return tmp;
    }
    Matrix operator * (const Matrix &b) const{
        Matrix tmp;
        tmp.clear();
        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 get(int x){//幂运算
        Matrix E;
        E.clear();
        E.n=E.m=n;
        for(int i=0;i<n;++i)
            E.a[i][i]=1;
        if(x==0) return E;
        else if(x==1) return *this;
        Matrix tmp=get(x/2);
        tmp=tmp*tmp;
        if(x%2) tmp=tmp*(*this);
        return tmp;
    }
};
//矩阵模板结束

int main(){

    while(cin>>r>>mod){
        if(r==0) break;
        int a[]= {1,1,5,11};
        if(r<=3)
        {
            cout<<a[r]%mod<<endl;
            continue;
        }
        Matrix A;
        A.clear();
        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;
        A=A.get(r-3);
        Matrix M;
        M.clear();
        M.n=4;M.m=1;
        M.a[0][0]=M.a[1][0]=1;
        M.a[2][0]=5;
        M.a[3][0]=11;
        M=A*M;
        cout<<(M.a[3][0]+mod)%mod<<endl;
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值