【题目链接】:click here~~
骨牌,一种古老的玩具。今天我们要研究的是骨牌的覆盖问题:
我们有一个2xN的长条形棋盘,然后用1x2的骨牌去覆盖整个棋盘。对于这个棋盘,一共有多少种不同的覆盖方法呢?
举个例子,对于长度为1到3的棋盘,我们有下面几种覆盖方式:

第1行:1个整数N。表示棋盘长度。1≤N≤100,000,000
第1行:1个整数,表示覆盖方案数 MOD 19999997
62247088
17748018
我们考虑在已经放置了部分骨牌(灰色)的情况下,下一步可以如何放置新的骨牌(蓝色):

当N很小的时候,我们直接通过递推公式便可以计算。当N很大的时候,只要我们的电脑足够好,我们仍然可以直接通过递推公式来计算。
但是我们学算法的,总是这样直接枚举不是显得很Low么,所以我们要用一个好的算法来加速(装X)。
事实上,对于这种线性递推式,我们可以用矩阵乘法来求第n项。对于本题Fibonacci数列,我们希望找到一个2x2的矩阵M,使得(a, b) x M = (b, a+b),其中(a,
b)和(b, a+b)都是1x2的矩阵。
显然,只需要取M = [0, 1; 1, 1]就可以了:





代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL MOD=19999997;
LL N;
int i,j;
struct Matrlc
{
LL mapp[2][2];
} ans,base;
Matrlc unit= {1,0,0,1};
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] =base.mapp[0][1]=base.mapp[1][0]=1;
base.mapp[1][1]=0;
ans.mapp[0][0] = ans.mapp[1][1] = 1;// ans 初始化为单位矩阵
ans.mapp[0][1] = ans.mapp[1][0] = 0;
while(n)
{
if(n&1) ans=mult(ans,base);
base=mult(base,base);
n>>=1;
}
return ans.mapp[0][1]%MOD;
}
int main()
{
scanf("%lld",&N);
printf("%lld\n",pow(N+1)%MOD);
return 0;
}原文地址:http://blog.csdn.net/u013050857/article/details/46418859