面试题9(变形):矩形覆盖
题目链接:http://ac.jobdu.com/problem.php?pid=1390
思路:设用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形的方法数为Fn
1、考虑最后一个小矩形,假设他是竖着的,那么前n-1个小矩形可以任意放,有Fn-1种放法
2、考虑最后两个小矩形,假设他们都是横着放,那么前n-2个小矩形可以任意放,有Fn-2中放法
上面两种情况是否既包含n个小矩形的所有放法,又不存在重复计算呢?
首先考虑是否会重复,显然不会,最后两个小矩形的放法不一样,不可能重复。
再考虑是否包含了所有情况,我们可以换个角度想想,有没有一种放法不对应到上面的两种情况之一,
我们只能考虑最后两个是否没对应上,因为前面的n-2个包含了所有放法,显然不会出现不对应的情况。
递推公式:Fn = Fn-1 + Fn-2
注:考虑递推时,最重要的是,不重不漏!!!
code:
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 const int M = 2; 5 const int MOD = 1000000007; 6 typedef long long LL; 7 LL ans[M][M]; 8 LL tmp[M][M]; 9 10 // 矩阵乘法 11 void matrixMul(LL mat1[M][M], LL mat2[M][M]) 12 { 13 LL mat3[M][M]; 14 for (int i = 0; i < M; ++i) 15 { 16 for (int j = 0; j < M; ++j) 17 { 18 mat3[i][j] = 0; 19 for (int k = 0; k < M; ++k) 20 mat3[i][j] += mat1[i][k] * mat2[k][j]; 21 } 22 } 23 memcpy(mat1, mat3, sizeof(mat3)); 24 } 25 26 // 矩阵快速幂 27 void matrixQuickMod(int n) 28 { 29 tmp[0][0] = 1; 30 tmp[0][1] = 1; 31 tmp[1][0] = 1; 32 tmp[1][1] = 0; 33 34 // 将ans处理成单位矩阵 35 memset(ans, 0, sizeof(ans)); 36 for (int i = 0; i < M; ++i) ans[i][i] = 1; 37 38 while (n) 39 { 40 if (n & 1) matrixMul(ans, tmp); // 当n为奇数时,跟新ans 41 n >>= 1; 42 matrixMul(tmp, tmp); // 当n为偶数时跟新tmp 43 } 44 } 45 46 int main() 47 { 48 int n; 49 while (scanf("%d", &n) != EOF) 50 { 51 matrixQuickMod(n); 52 printf("%lld\n", ans[0][0]); 53 } 54 return 0; 55 }