hihoCoder #1143 : 骨牌覆盖问题·一   (斐波那契数列)

 

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

 

思路:这是斐波那契数列啊,f[n] = f[n-1] + f[n-2],初始时 f[0]=1,f[1]=1,f[2]=2。其实跟下面的递推思路差不多吧。但是关于这种简单,一般都可以用矩阵快速幂解决,即O(logn)时间内解决。主要难点是构造初始矩阵,如果是后面一个数字是由卡面两个数字相加而成的,那么一般可构造一个2*2的01矩阵,才这么小,随便试试吧,只要乘完的结果第二位是答案即可。

 

 

 

 1 #include <iostream>
 2 using namespace std;
 3 const int yu = 19999997;
 4 const int MASK = 1;
 5 struct fuf
 6 {    
 7     long long a,b,    //矩阵如左
 8               c,d;
 9 }q[33];
10 
11 int handle_it()
12 {
13     q[0].a=0; q[0].b=1; q[0].c=1; q[0].d=1;    //矩阵M的1次方
14     int i=1;
15     for(; i<=32; i++)    //作乘
16     {
17         q[i].a = ( q[i-1].a * q[i-1].a + q[i-1].b * q[i-1].c )%yu;
18         q[i].b = ( q[i-1].a * q[i-1].b + q[i-1].b * q[i-1].d )%yu;
19         q[i].c = ( q[i-1].c * q[i-1].a + q[i-1].d * q[i-1].c )%yu;
20         q[i].d = ( q[i-1].c * q[i-1].b + q[i-1].d * q[i-1].d )%yu;
21     }
22     return 0;
23 }
24 int main()
25 {
26     handle_it();
27     int n;
28     while( cin>>n )
29     {
30         if( n>0 && n<=3)     {cout<<n<<endl;continue;}
31         int i=0;
32         while( (n&MASK)==0 )        //直到n后面的0被去掉
33         {
34             i++;
35             n >>= 1;
36         }
37         fuf ans = q[i++];
38         n >>= 1;
39         for( ; i<32 && n!=0; i++,n >>= 1)
40         {
41             if( (n&1)==1 )
42             {
43                 fuf tmp;
44                 tmp.a = ( ans.a * q[i].a + ans.b * q[i].c )%yu;
45                 tmp.b = ( ans.a * q[i].b + ans.b * q[i].d )%yu;
46                 tmp.c = ( ans.c * q[i].a + ans.d * q[i].c )%yu;
47                 tmp.d = ( ans.c * q[i].b + ans.d * q[i].d )%yu;
48                 ans = tmp;
49             }
50         }
51         cout<<ans.d<<endl;
52     }
53     return 0;
54 }
骨牌

相关文章: