题目大意是用1*2的骨牌堆积成4*N的矩形。一共同拥有多少种方法,N不超过10^9。
这题和以前在庞果网上做过的一道木块砌墙差点儿一样。
由于骨牌我们能够横着放。竖着放。我们如果以4为列,N为行这样去看,而且在骨牌覆盖的位置上置1,所以一共最多有16种状态。我们在第M行放骨牌的时候,第M+1行的状态也是有可能被改变的,设S(i,j)表示某一行状态为i时,将其铺满后下一行状态为j的方案书。考虑下如果我们让矩阵S和S相乘会有什么意义。考虑一下会发现S*S的意义当某行状态为i。接着其后面第2行的状态为j的可行方案数,一般地,S^n则代表接下来第n行状态为j的方案数,这里N非常大,我们能够用高速幂对矩阵的幂进行加速。
对于S矩阵的最初状态我们能够穷尽搜索来求。
#include <stdlib.h> #include <stdio.h> #include <vector> #include <math.h> #include <string.h> #include <string> #include <iostream> #include <queue> #include <list> #include <algorithm> #include <stack> #include <map> #include<iostream> #include<cstdio> using namespace std; int State[16][16]; int Start[16][16]; int IMod; void InitState(int ori, int s, int p) { bool isfull = true; for (int i = 0; i < 4; i++) { if (((s >> i) & 1) == 0) { //竖着放 InitState(ori, s | (1 << i), p | (1 << i)); //横着放 if (i < 3 && ((s >> (i + 1)) & 1) == 0) { int tp = s | (1 << i); tp |= (1 << (i + 1)); InitState(ori ,tp, p); } isfull = false; break; } } if (isfull) { State[ori][p] += 1; } } void Product(int a[][16], int b[][16], int res[][16]) { for (int i = 0; i < 16;i++) { for (int j = 0; j < 16; j++) { res[i][j] = 0; for (int k = 0; k < 16; k++) { res[i][j] += (a[i][k] * b[k][j] % IMod); res[i][j] %= IMod; } } } } void QProduct(int p[][16], int res[16][16], int n) { memset(res, 0, sizeof(int) * 16 * 16); int tmp[2][16][16]; int tmpres[16][16]; memcpy(tmp[0], p, sizeof(int) * 16 * 16); int i = 0; for (int k = 0; k < 16; k++) { res[k][k] = 1; } while (n) { if (n & 1) { memcpy(tmpres, res, sizeof(int) * 16 * 16); Product(tmpres, tmp[i & 1], res); } Product(tmp[i & 1], tmp[i & 1], tmp[(i + 1) & 1]); i++; n = n >> 1; } } int main() { #ifdef _DEBUG freopen("d:\in.txt", "r", stdin); #endif int n, m; memset(State, 0, sizeof(State)); for (int i = 0; i < 16; i++) { InitState(i, i, 0); } int finstates[16][16]; int res[16][16]; memset(Start, 0, sizeof(Start)); Start[0][0] = 1; while (scanf("%d %d", &n, &m) != EOF) { if (n == 0 || m == 0) { break; } IMod = m; QProduct(State, finstates, n); Product(Start, finstates, res); int ans = 0; for (int i = 0; i < 16; i++) { ans += res[i][0]; ans %= IMod; } printf("%d ", ans); } return 0; }