Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 3422 | Accepted: 1492 |
Description
Tired of the Tri Tiling game finally, Michael turns to a more challengeable game, Quad Tiling:
In how many ways can you tile a 4 × N (1 ≤ N ≤ 109) rectangle with 2 × 1 dominoes? For the answer would be very big, output the answer modulo M (0 < M ≤ 105).
Input
Input consists of several test cases followed by a line containing double 0. Each test case consists of two integers, N and M, respectively.
Output
For each test case, output the answer modules M.
Sample Input
1 10000 3 10000 5 10000 0 0
Sample Output
1 11 95
前序分析见我的另一篇博客,传送门:poj2411题解
这题其实采用的是poj2411的第二种方法,但是利用第二种方法,我们发现行数太多,必然超时。
但是我们观察poj2411每重for做了一件什么事?
对于m列,我们有1<<m个状态,状态之间有转移关系,我们将这些状态看成点,那么这些点之间的关系看成距离为1的路径,那么每重for其实是在原先到达情况下,又多走了距离1,也就是相当于做了k重for表示距离小于等于k的路径条数,这个正好是可达矩阵的k次方,突然吓傻,矩阵快速幂搞起啊!
最后,因为第0行我们假设是全1状态这样可以保证不影响第一行的方法,而最终状态也是全1,也就是本题转化为从点15走到点15,距离小于等于n的路径条数。
代码:
#include<cstdio> #include<iostream> #include<cstring> #define Maxn 20 using namespace std; int mod; int d; struct matrix{ long long mat[Maxn][Maxn]; matrix(){memset(mat,0,sizeof mat);} matrix operator*(matrix &x){ matrix ans; for(int i=0;i<d;i++) for(int j=0;j<d;j++) for(int k=0;k<d;k++){ ans.mat[i][j]+=mat[i][k]*x.mat[k][j]; ans.mat[i][j]%=mod; } return ans; } }x; matrix quick_pow(matrix x,int k){ matrix ans; for(int i=0;i<d;i++) ans.mat[i][i]=1; while(k){ if(k&1) ans=ans*x; x=x*x; k>>=1; } return ans; } int n,m; void dfs(int c,int s,int scur){ if(c>4) return; if(c==4){ x.mat[s][scur]=1; return; } dfs(c+1,s<<1,scur<<1|1); dfs(c+1,s<<1|1,scur<<1); dfs(c+2,s<<2|3,scur<<2|3); } int main() { while(cin>>n>>mod,n){ memset(x.mat,0,sizeof x.mat); dfs(0,0,0); d=16; x=quick_pow(x,n); cout<<x.mat[15][15]<<endl; } return 0; }