問題の意味
の$ n \倍メートルの$グリッドを考えると、各グリッドは黒または白染色しました。今$ 1 \回2 $レンガブロックの間に必要と重ならず、グリッドを網羅使用し、すべての白の格子をカバーしていますが、黒い四角のいずれかをカバーしていません。どのように多くの方法の合計をカバーしようとしています。結果は、$ M $の残りを取ります。($ 1 \当量のn \の当量15、1 \当量のM \の当量15 $)
分析
爆発の検索、それぞれが1を返すように解決策を見つけ、上から下へ、左から右へ、左上から始まります。
#include <ビット/ STDC ++ H> 使用して 名前空間STDを、 typedefの長い 長いLL。 const int型のmod = 1000000007 ; INTのN、M。 CONSTの INT MAXN = 15 + 5 。 ブール色[MAXN] [MAXN]。 // 偽の为の白、真の为黑 ブール[MAXN] [MAXN]使用。 INT REC(int型 I、INT J) { 場合(jは== mの) 戻り REC(I + 1、0); // 进入下一行 の場合(I == N-) のリターンを 1。 ; // すべてのスペースをカバーしている のIF(中古[I] [J]の色は|| [I] [J]) を返す REC(I、J +を1。); // (私には必要ありません。 、j)はレンガ上に配置される // 放電方式の二種類試みる INT RES = 0 ; 中古[I] [J]は、 = trueに; // 横放電 IF(J + 1 <M &&中古[I]、[J +!1。 ] && !色[I]、[Jの+ 1 ]) { [Jの中古[I] + 。1 ] = trueに、 RES + = REC(I、J)。 使用[I]、[J +1 ] = 偽。 } // 竖着放 場合(I + 1 <N &&使用[I +!1 ] [J] &&色[I +!1 ] [J]) { 使用[I + 1 ] [j]は= 真。 RES + = REC(I、J + 1 )。 使用[I + 1 ] [j]は= 偽。 } [I] [j]が使用 = 偽。 返すのres%のmod。 } int型のmain() { // INIT色 scanf関数(" %d個の%のD "、&N、&M)。 printf(" %dの、"、REC(0、0 )); } }
この方法の時間計算量は$ O($ NM \ CDOT 2 ^ {NM})$、タイムアウトです。あなたは、メモリの検索を使用することはできません。
しかし、慎重な検討が実際のパラメータは、この多くの可能なを持っていないことがわかります。
各列の格子トップの種類だけ不確実性は、まだ$ M $の合計クエリではなかったです。これは、$ M $格子ステートメモリ検索コードによって行うことができる、複雑さが$ $ O(2 ^ {M} nmでの\ CDOT)です。
#include <ビット/ STDC ++ H> 使用して 名前空間STDを、 typedefの長い 長いLL。 const int型のmod = 1000000007 ; INTのN、M。 CONSTの INT MAXN = 15 + 5 。 const int型 M = 十億七。 ブール色[MAXN] [MAXN]。 // 偽の为の白、真の为黑 int型 DP [ 2 ] [ 1 << MAXN]; ボイド解く() { int型 * CRT = DP [ 0 ]、* NXT = DP [ 1]; CRT [ 0 ] = 1 ; 以下のために(int型 I = N- 1、I> = 0 ; i-- ) のための(INT J = M- 1 ; J> = 0 ; j-- ) { ため(intです使用= 0 ; <使用(1 << M); ++使用) { 場合((使用>> J&1)|| 色[I] [J]) NXTが[使用] = CRT [使用&〜(1 << J)]。 // 不需要在(i、j)を放置砖块 他に { // 尝试2种放法 int型のres = 0 ; もし(J + 1!<M &&((使用>>(J + 1))&1!)&&色[I] [J + 1 ]) // 横着放 使用RES + = CRT [| (1 <<(j + 1 ))]。 もし(私は+ 1!<N &&色[I + 1 ] [J]) RES使用+ = CRT [| (1 << J)]。 // 竖着放 NXT [使用] =のRESの%M。 } } スワップ(CRT、NXT)。 } のprintf(" %d個の\ n "、CRT [ 0 ])。 } int型のmain() { // INIT色 のscanf(" %D%dの"、&N、&M)。 解決する(); }
From:「課題はコンテストのプログラミング」