zoukankan      html  css  js  c++  java
  • 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 }
    骨牌

      写了个递推的思路:

      (1)设dp[i]表示2*(i-1)的棋盘的摆放种数。

      (2)假设第i列是放一个竖的,那么dp[i+1]+=dp[i]。这样只是一种,所以只是单纯用加的方式。

      (3)假设第i列是放横的,那么连同第i+1列都被占用了,所以第i和i+1列就被摆放了两个横的,那么dp[i+2]+=dp[i]。这又是一种。

      (4)2*n的棋盘答案就自然是dp[n+1]了,表示前n列的摆放种数。

     1 #include <bits/stdc++.h>
     2 #define pii pair<int,int>
     3 #define INF 0x3f3f3f3f
     4 #define LL long long
     5 using namespace std;
     6 const int N=1e8+2;
     7 const int mod=19999997;
     8 int dp[N], ans[N];
     9 void pre_cal()
    10 {
    11     dp[1]=1;
    12     for(int i=1; i<N; i++)
    13     {
    14         dp[i+2]=(dp[i+2]+dp[i])%mod;    //考虑放横
    15         dp[i+1]=(dp[i+1]+dp[i])%mod;    //考虑放直
    16         ans[i]=(dp[i]+dp[i-1])%mod;
    17     }
    18 }
    19 
    20 int main()
    21 {
    22     freopen("input.txt", "r", stdin);
    23     pre_cal();
    24     int  n;
    25     while(~scanf("%d",&n))    printf("%d
    ",ans[n]);
    26     return 0;
    27 }
    TLE代码
  • 相关阅读:
    汉诺塔
    破损的键盘
    解方程
    运输计划
    选学霸
    子集和的目标值
    棋盘染色2
    守卫者的挑战
    飞扬的小鸟
    攻克城堡
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4423691.html
Copyright © 2011-2022 走看看