时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
骨牌,一种古老的玩具。今天我们要研究的是骨牌的覆盖问题:
我们有一个2xN的长条形棋盘,然后用1x2的骨牌去覆盖整个棋盘。对于这个棋盘,一共有多少种不同的覆盖方法呢?
举个例子,对于长度为1到3的棋盘,我们有下面几种覆盖方式:
提示:骨牌覆盖
提示:如何快速计算结果
输入
第1行:1个整数N。表示棋盘长度。1≤N≤100,000,000
输出
第1行:1个整数,表示覆盖方案数 MOD 19999997
样例输入
62247088
样例输出
17748018
http://hihocoder.com/contest/hiho41/problem/1
#include <iostream>
using namespace std;
const int yu = 19999997;
const int MASK = 1;
struct fuf
{
long long a,b, //矩阵如左
c,d;
}q[33];
int handle_it()
{
q[0].a=0; q[0].b=1; q[0].c=1; q[0].d=1; //矩阵M的1次方
int i=1;
for(; i<=32; i++) //作乘
{
q[i].a = ( q[i-1].a * q[i-1].a + q[i-1].b * q[i-1].c )%yu;
q[i].b = ( q[i-1].a * q[i-1].b + q[i-1].b * q[i-1].d )%yu;
q[i].c = ( q[i-1].c * q[i-1].a + q[i-1].d * q[i-1].c )%yu;
q[i].d = ( q[i-1].c * q[i-1].b + q[i-1].d * q[i-1].d )%yu;
}
return 0;
}
int main()
{
handle_it();
int n;
while( cin>>n )
{
if( n>0 && n<=3) {cout<<n<<endl;continue;}
int i=0;
while( (n&MASK)==0 ) //直到n后面的0被去掉
{
i++;
n >>= 1;
}
fuf ans = q[i++];
n >>= 1;
for( ; i<32 && n!=0; i++,n >>= 1)
{
if( (n&1)==1 )
{
fuf tmp;
tmp.a = ( ans.a * q[i].a + ans.b * q[i].c )%yu;
tmp.b = ( ans.a * q[i].b + ans.b * q[i].d )%yu;
tmp.c = ( ans.c * q[i].a + ans.d * q[i].c )%yu;
tmp.d = ( ans.c * q[i].b + ans.d * q[i].d )%yu;
ans = tmp;
}
}
cout<<ans.d<<endl;
}
return 0;
}