铺砖问题
Description
用1×2的 砖头铺满N*M的区域,不能有重叠,一共有多少种方案?如下图所示:
Data Constraint
20%的数据满足1<=N,M<=6
50%的数据满足1<=N<=100,1<=M<=11
另外50%的数据满足1<=N<=10^200,1<=M<=5
Analysis
对于此题的前50%的数据
可以参照此位大神的解析:
http://blog.csdn.net/yan_____/article/details/8719748
我的程序前50%就是参考了这篇文章
对于100%的数据
- 我们发现N很大,但是M却很小。
- 前50%的数据我们都是通过不同的二进制状态转移并累加得到的。这种转移就显然就是矩阵自乘的结果。而他的答案就是$a[(1 shl m)-1,(1 shl m)-1]$,表示从(1 shl m)-1转移到(1 shl m)-1的方案数。
- 那么我们可以将前50%数据得到的st数组中的对应值映射到[0..1 shl m,0..1 shl m]的矩阵中,然后将这个矩阵自乘n次即可得到答案。
- 矩阵自乘可以用快速幂进行优化。
- 因为做一次矩阵乘法的时间复杂度为$O(N^3)$。所以整体的时间复杂度为$O((2^m)^3*log(10^100)/log(2))$。
- 因为n极其的庞大所以在做快速幂时我们需要用到单精除。
- 可能很多人会不理解为什么用矩阵乘法和为什么答案是$a[(1 shl m)-1,(1 shl m)-1]$。(懂得人可以忽略此部分内容)
对于每一层来说,因为st数组中$st[i][0] $都可以到$st[i][1]$ 。所以我们首先想想最简单的情况:
当n=1时,他的答案就是从$dp[0][1 shl m-1]$ 到$dp[1][1 shl m-1] $。就是 $base[1 shl m -1] [1 shl m-1]$。
当n=2 时,我们可以看看矩阵乘法的工作原理 对于答案$ans[i,j] += a[i,k]*a[k,j]$,他是通过枚举k将第i行和第j列一一对应相乘并累加的道德结果。而在我们的基础矩阵base存放的就是第i行的状态可以转移到哪j个状态。当你要从i这个状态到j这个状态,我们可以枚举一个中间点k让i先到k,再从k到j
,这样恰好进行了两次转移所以这个ans矩阵,就代表从第i个状态经过了n次转移(看你乘了多少次)到达第j个状态的方案数。
其实矩阵乘法可以类比floyd求最短路的算法。
Code
因为代码比较丑,所以不要见怪
1 | const maxn=100+5;maxm=10+5; |
Tips
此题源自:zoj1100
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1100
据说此题有通项公式,具体请看维基百科
https://en.wikipedia.org/wiki/Domino_tiling