1. 程式人生 > >CCF201409-5拼圖(狀態壓縮DP+矩陣快速冪) (骨牌覆蓋問題拓展 )

CCF201409-5拼圖(狀態壓縮DP+矩陣快速冪) (骨牌覆蓋問題拓展 )

文章目錄

拼圖

題意:

在這裡插入圖片描述

分析:

這是hiho1143 && hiho 1151&&1033 骨牌覆蓋 V2的拓展
搜尋確定狀態轉移方程,快速冪加速運算


LL NN,N,M;
// 注意修改maxn 的值,要不然容易T
// 注意maxn值過大,棧可能會不夠
const int maxn = 200;
struct Matrix{
  int n,m;
  Matrix(int nn = 1,int mm = 1):n(nn)
,m(mm){ memset(a,0,sizeof(a));}; long long a[maxn][maxn]; }; void print(const Matrix &a) { for(int i = 1;i <= a.n; ++i,cout<<endl) // cout<<i<<" "; { cout<<i<<" "; for(int j= 1;j <= a.m; ++j) // cout<<a.a[i][j]<<" "; printf("%2lld "
,a.a[i][j]); } // cout<<e } Matrix operator*(Matrix a,Matrix b) { Matrix c(a.n,b.m); for(int i = 1;i <= a.n; ++i) { for(int j = 1;j <= b.m; ++j) { for(int k = 1;k <= a.m; ++k) { c.a[i][j] += a.a[i][k] * b.a[k][j]; c.a[i][j] %= mod; } }
} // print(c); return c; } int MM[maxn][maxn]; void dfs(int a,int now,int nxt){ if(((now&(NN-1) )== (NN-1))) { // if(a == 4) // cout<<nxt<<endl; // cout<<a<<endl; MM[a][nxt]++; return ; } // cout<<now<<endl; for(int i = 0;i < N; ++i){ // 情況1 // 01 if((now>>i) & 1) continue; if(i != 0 && !((nxt >>(i-1)) &1)) dfs(a,now|(1<<i),nxt|(1<<i)|(1<<(i-1))); if(i + 1 < N && ((now >> (i+1))&1)) dfs(a,now|(1<<i),nxt|(1<<i)|(1<<(i+1))); if(i + 1 < N && !(now>>(i+1)&1)){ dfs(a,now|(1<<i)|(1<<(i+1)),nxt|(1<<i)); dfs(a,now|(1<<i)|(1<<(i+1)),nxt|(1<<(i+1))); if(i+2 < N && !(now>>(i+2)&1)){ dfs(a,now|(1<<i)|(1<<(i+1))|(1<<(i+2)),nxt|(1<<i)|(1<<(i+1))|(1<<(i+2))); } } break; } } Matrix ans,B; int main(void) { scanf("%lld %lld",&M,&N); NN = 1<<N; // cout<<NN<<endl; for(int i = 0;i < NN; ++i){ dfs(i,i,0); } ans.n = ans.m = B.n = B.m = NN; for(int i = 1;i <= NN; ++i){ for(int j = 1;j <= NN; ++j){ B.a[i][j] = MM[i-1][j-1]; } } // for(int i = 1;i <= NN; ++i) // printf("%2d ",i); // cout<<endl; // print(B); ans.a[1][1] = 1; while(M > 0){ if(M & 1) ans = ans*B; B = B*B; M >>= 1; } cout<<ans.a[1][1]<<endl; return 0; }