31 经典矩阵快速幂

C - Macarons

C: Macarons

Pierre is famous for his macarons. He makes round macarons, stored in square boxes of size

1×1, andoval-shaped macarons, stored in rectangular boxes of size1×2 (or, rotated, in rectangular boxes ofsize2×

1). For the purpose of a buffet, Pierre wishes to tile a rectangular table of sizeN×Mwith thetwo kinds of macarons, meaning that the table must be completely full, with no empty space left. ThewidthNof the table is small, for the guest to be able to grab the macarons easily, and the lengthMofthe table is large, to accommodate a huge number of guests. To keep the table pretty, the orientation of macarons should always be aligned with the sides of the table. Pierre wishes to know how many ways there are to tile the table. Can you help him?

Input

The input consists of the following integers:•

the value ofN, an integer, on the first line;•he value ofM, an integer, on the second line.LimitsThe input satisfies
题目的意思非常简单就是给你一个n行m列的格子,让你用1*1或是1*2的格子将他填满,有多少种不同的方案,这是一道经典的矩阵快速幂题目,这道题目的解决方案分为两部分,一部分是建图,另外一部分是用矩阵快速幂来求算方案数目,第一部分建图用DFS枚举状态建图

1)对于建图,就是一个用二进制的数来表示每一个状态,如果当前状态可以到达下一个状态,那么就是有一条有向边从当前的点到达下一个点就是图中有一条有向边,下面是详细的状态分析假设我们的n=2,m=2;假设这个时候我们m-1列是没有填满的  

    列         :    m-1          m

   状态  1  :     0

                         0        

   状态   2 :     1

                         0

  状态   3  :     0

                         1

 状态   4   :     1

                         1

假设我们现在到了m-1列了,我们要把第m-1列给填满的同时,在m列会产生那些情况呢,0表示这一行这一列没有格子,1表示这一行这一列有一个格子;

对于状态1我们可以放两个1*1的格子那么m-1列就满了,但是m列一个格子也没有所以就有一条边 0-->0,

                 我们放一个1*1,在横着放一个1*2的格子那么在第m列就有(1<<1)1 )=2,就有0-->2一条边,

                 我们横着放一个1*2的格子,然后在放一个1*1的格子,在m列的状态就是1,那么我们就是有0-->1一条边;

                 我们横着放一个1*2的格子,然后在横着放一个1*2的格子,在m列的状态就是3,那么我们有0-->3一条边;

                 如果我们竖着放一个1*2的格子那么,在m列就还是0,我们又得到一条0-->0的边,

状态1分析完后的图

对于状态2,3,4是类似的,(注意如果是在递归的时候我们在定义变量的时候要注意不要定义城全局变量,可能在回溯的时候无法保存一下我们想要的值)

方案数,就是给你一个有向图,然后给你始末点,让你算一下所有的方案数,这里就是一个矩阵乘法,因为我们可以这么想,有两个点,我们可以枚举第三个点,并且这个点是另外两个点的中间点,可以从一个点经过这个点,到另外的一个点方案数,sum[s][e]=for(int i=1;i<=n;i++)  sum[s][e]=sum[s][i]*sum[i][e];

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Max = 10;
const ll mod = 1e9;
#define rep(i,s,n) for(ll i=s;i<=n;i++)
ll a[Max][Max];
int one[Max];
void DFS(ll s, ll now, ll nex, ll n){
   memset(one,0,sizeof(one));
   ll tnow=now, tnex=nex;
   int num=0;
   while(now){
    one[num++]=now%2;
    now/=2;
   }
   int f=1;
   rep(i,0,n-1){
      if(one[i]==0){
        f=0;
        break;
      }
   }
   if(f) {
    a[s][tnex]++;
    return ;
   }//如果是当前的这一列上全是1了说明这一列满了,此时的状态tnex可以到达;
   rep(i,0,n-1){
     if(one[i]==0){
        DFS(s,tnow+(1<<i),tnex,n);//用1*1的格子进行对当前的列进行补满;
        DFS(s,tnow+(1<<i),tnex|(1<<i),n);//用1*2的格子对当前列进行补满,横着放;
        if(i+1<=n-1&&one[i+1]==0){
            DFS(s,tnow+(1<<i)+(1<<(i+1)),tnex,n);//对当前的列用1*2进行补满,竖着放;
        }
     }
   }
}
void multi(ll res[][10],ll a[][10], ll n){
    ll c[10][10];
    rep(i,0,9){
      rep(j,0,9) c[i][j]=0;
    }
    rep(i,0,n-1){
      rep(j,0,n-1){
         rep(k,0,n-1){
           c[i][j]=(c[i][j]+res[i][k]*a[k][j]%mod)%mod;
           c[i][j]=(c[i][j]%mod+mod)%mod;
         }
      }
    }
    rep(i,0,n-1){
      rep(j,0,n-1){
        res[i][j]=c[i][j];
      }
    }
}
void pow1(ll res[][10],ll a[][10], ll k, ll n){
   rep(i,0,9)  {
       rep(j,0,9){
         if(i==j) res[i][j]=1;
         else res[i][j]=0;
       }
   }
   while(k){
    if(k&1) multi(res,a,n);
    multi(a,a,n);
    k>>=1;
   }
}
int main(){
  ll n,m;
  scanf("%lld %lld",&n,&m);
  int N=1<<n;
  rep(i,0,N-1){
    DFS(i,i,0,n);
  }
  ll res[Max][Max];
  pow1(res,a,m,n);
  printf("%lld\n",res[0][0]);
  return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39792342/article/details/82685591
31
31)