题目链接
Submit your solution Discuss this problem Best solutions |
Time Limit: 1000ms
3 1 10000 2 10000 5 10000
1 5 95
题意:4*n的矩形,用1*2的矩形来填,问有多少种方式可以将其填满?
题解:容易想到状压dp。用dp[i][j] 表示前i-1行已经填满,第 i 的填的状态为 j 的方案数。由于n的范围很大,所以要用到矩阵优化。
这里有一个知识点:如果一个图用一个n*n的矩阵表示,a[i][j] 表示点i到点j的边数。那么这个矩阵求x幂后,a[i][j]表示从点i到点j ,经过x条边有多少种走法?
所以这里我们根据转移方程,建一个16*16的矩阵,如果i状态能转移到j状态则a[i][j]=1。那么对于这个矩阵求n次幂后,a[15][15]就是最后的答案。
代码如下:
#include<cstdio> #include<cstring> #include<set> #include<iostream> #include<map> #include<cmath> #include<string> #include<vector> #include<queue> #include<cctype> #include<algorithm> #define inf 0x3fffffff #define nn 1100 #define mod 1000000007 typedef long long LL; using namespace std; int n,m; struct Matrix { LL a[20][20]; int n1,n2; void init() { n1=n2=16; memset(a,0,sizeof(a)); } Matrix operator * (const Matrix &b)const { Matrix tmp; tmp.init(); tmp.n1=n1,tmp.n2=b.n2; for(int i=0;i<n1;i++) { for(int j=0;j<b.n2;j++) { for(int k=0;k<n2;k++) { tmp.a[i][j]+=a[i][k]*b.a[k][j]; tmp.a[i][j]%=m; } } } return tmp; } }dw,tem,ans; void init() { dw.init(); int i,j,k; for(i=0;i<16;i++) { for(j=0;j<16;j++) { dw.a[i][j]=i==j?1:0; } } tem.init(); int ix; for(i=0;i<16;i++) { for(j=0;j<16;j++) { if((i^j)==15) { tem.a[i][j]=1; } else { if((i|j)==15) { ix=i&j; for(k=0;k<4;k++) { if((1<<k)&ix) { if((1<<(k+1)&ix)) { k++; } else break; } } if(k>=4) { tem.a[i][j]=1; } } } } } } Matrix po(Matrix x,int y) { Matrix re=dw; while(y) { if(y%2) { re=re*x;; } x=x*x; y/=2; } return re; } int main() { int t; init(); scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); ans=po(tem,n); printf("%lld\n",ans.a[15][15]); } return 0; }