標籤:
題意:有一個k*n的棋盤,要求用1*2的骨牌來鋪滿,有多少種方案?(k<8,n<100000001)
思路:
由於k是比較小,但是又不那麼小,可以專門構造這樣的一個矩陣M,使得只要我們有一個初始矩陣R,求得ans矩陣,然後答案就在ans中了。ans=R*Mn。
M的大小應該是2k*2k,所以當k稍微大一些就不合適儲存這個矩陣了,而且裡面大部分都是0,很浪費。由於k<8,所以M的大小為128*128是可以接受的。複雜度是O(23*k*logn),大概是千萬層級的。
1 #include <bits/stdc++.h> 2 #define pii pair<int,int> 3 #define INF 0x3f3f3f3f 4 #define LL long long 5 using namespace std; 6 const int N=21000; 7 const int mod=12357; 8 int k, n; 9 int M[130][130], grid[130][130], tot[130][130], cur[130][130];10 11 void DFS(int x,int y,int col) //構造矩陣M。12 {13 if(col==k)14 {15 M[y][x]=1; //表示y可以轉移到x16 return ;17 }18 DFS(x<<1, (y<<1)+1, col+1); //不放19 DFS((x<<1)+1, y<<1, col+1); //放豎20 if(col+2<=k) DFS((x<<2)+3, (y<<2)+3, col+2); //放橫21 }22 23 void mul(int A[][130],int B[][130])24 {25 for(int i=0; i<(1<<k); i++)26 {27 for(int j=0; j<(1<<k); j++)28 {29 int tmp=0;30 for(int q=0; q<(1<<k); q++)31 {32 tmp+=A[i][q]*B[q][j];33 tmp%=mod;34 }35 grid[i][j]=tmp;36 }37 }38 memcpy(A, grid, sizeof(grid));39 }40 41 42 int cal(int t) //注意t=n-143 {44 memset(M, 0, sizeof(M));45 memset(tot, 0, sizeof(tot) );46 memset(cur, 0, sizeof(cur) );47 DFS( 0, 0, 0); //求矩陣。48 memcpy(cur, M, sizeof(M));49 while(t)50 {51 if(t&1) mul(M, cur); //該位為152 mul(cur, cur); //矩陣自乘53 t>>=1;54 }55 return M[(1<<k)-1][(1<<k)-1]; //矩陣很特殊,只需要這一項。56 }57 58 int main()59 {60 //freopen("input.txt", "r", stdin);61 while(~scanf("%d%d", &k, &n)) printf("%d\n", cal(n-1));62 return 0;63 }AC代碼
hihoCoder #1162 : 骨牌覆蓋問題·三 (矩陣快速冪,DP)