关闭

ZCMU-1618-骨牌覆盖(矩阵乘法+快速幂)

126人阅读 评论(0) 收藏 举报
分类:

1618: 骨牌覆盖1

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 264  Solved: 124
[Submit][Status][Web Board]

Description

我们有一个2xN的长条形棋盘,然后用1x2的骨牌去覆盖整个棋盘。对于这个棋盘,一共有多少种不同的覆盖方法呢?

Input

输入n,n<=100000

Output

覆盖方案总数对19999997取余

Sample Input

1
2

Sample Output

1
2

【解析】
这道题的话其实我们只要列举出前面几个数我们数一数方案我们就能知道是什么样的规律了,感觉很多题都是斐波那契数列,就算蒙,说不定也能蒙对了,还有这道题数据不大,所以我们更加好做,不过我在这里要说一下万一数据很大,我们怎么求斐波那契数列?在这里我要说一下矩阵乘法了。什么是矩阵乘法?把这些概念搞懂就差不多了。1.当矩阵A的列数等于矩阵B的行数时,A与B可以相乘。2.矩阵C的行数等于矩阵A的行数,C的列数等于B的列数。3.乘积C的第m行第n列的元素等于矩阵A的第m行的元素与矩阵B的第n列对应元素乘积之和。比如
我们可以用矩阵乘法来求n项,我们希望找到一个2x2的矩阵M,使得(a, b) x M = (b, a+b),其中(a, b)和(b, a+b)都是1x2的矩阵。a代表前一项,b代表的是后一项。我们这里M只要取[0,1;1,1];至于为什么我们可以自己去验证下。我们可以看一下图片上的例子。
这就是我们要做的事情矩阵直接不断的成不断的乘,最终我们的式子是这样子的
这个时候n其实是巨大的,我们这个时候想要快速的求出我们就需要用到快速幂的算法了。关于快速幂的问题可以看看这里http://blog.csdn.net/zcmuczx/article/details/53962502
我们很容易的知道a的n次方我们要求,就把n转换成二进制来求,因为你看5如果给他编码我们就取后几位101遇到1就表示它要开始乘了,就好比a的5次方其实就是a的4次方乘a所以我们遇到末尾的1相当于遇到5的1次乘起来,遇到倒数第三位的1就是5的四次了大家可以自己试一下。大概就是这么的思路接下来具体的看代码。
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
#define LL long long
#define MOD 19999997
LL N;
int i,j;
struct Matrlc
{
    LL mapp[2][2];//定义结构体,元素是一个矩阵
} ans,base;
Matrlc mult(Matrlc a,Matrlc b)
{
    Matrlc c;
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            c.mapp[i][j]=0;
            for(int k=0; k<2; k++)//矩阵乘法
            {
                c.mapp[i][j]+=(a.mapp[i][k]*b.mapp[k][j])%MOD;//这里是比如行的元素乘列的元素
            }
            c.mapp[i][j]%=MOD;
        }
    }
    return c;
}
LL pow(LL n)
{
    base.mapp[0][0] =0;
    base.mapp[0][1]=base.mapp[1][0]=base.mapp[1][1]=1;//初始化矩阵成0,1,1,1;
    ans.mapp[0][0] =1; ans.mapp[0][1] =0;// 把第一个矩阵我把他设为1,0,0,0,这样的话其实只有第一行的元素是有用的经过一次乘法
    ans.mapp[1][0]= ans.mapp[1][1] = 0;//变成了1,1,0,0这样就表示f[1]为1其实这样才是初始状态,所以我们下面才要pow(N+1)
    while(n)
    {
        if(n&1)
            ans=mult(ans,base);
        base=mult(base,base);//矩阵乘法
        n>>=1;
    }
    return ans.mapp[0][1]%MOD;
}
int main()
{
   while(~scanf("%lld",&N))
   {
   printf("%lld\n",pow(N+1)%MOD);
   }
   return 0;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:36172次
    • 积分:3891
    • 等级:
    • 排名:第8464名
    • 原创:361篇
    • 转载:37篇
    • 译文:0篇
    • 评论:7条
    文章分类
    最新评论