您的位置:首页 > 其它

hihoCoder #1162 : 骨牌覆盖问题·三 (矩阵快速幂,DP)

2015-09-03 21:20 267 查看
题意:有一个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),大概是千万级别的。

#include <bits/stdc++.h>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=21000;
const int mod=12357;
int k, n;
int M[130][130], grid[130][130], tot[130][130], cur[130][130];

void DFS(int x,int y,int col)   //构造矩阵M。
{
if(col==k)
{
M[y][x]=1;              //表示y可以转移到x
return ;
}
DFS(x<<1, (y<<1)+1, col+1);                      //不放
DFS((x<<1)+1, y<<1, col+1);                      //放竖
if(col+2<=k)    DFS((x<<2)+3, (y<<2)+3, col+2);  //放横
}

void mul(int A[][130],int B[][130])
{
for(int i=0; i<(1<<k); i++)
{
for(int j=0; j<(1<<k); j++)
{
int tmp=0;
for(int q=0; q<(1<<k); q++)
{
tmp+=A[i][q]*B[q][j];
tmp%=mod;
}
grid[i][j]=tmp;
}
}
memcpy(A, grid, sizeof(grid));
}

int cal(int t)  //注意t=n-1
{
memset(M, 0, sizeof(M));
memset(tot, 0, sizeof(tot) );
memset(cur, 0, sizeof(cur) );
DFS( 0, 0, 0);   //求矩阵。
memcpy(cur, M, sizeof(M));
while(t)
{
if(t&1) mul(M, cur);    //该位为1
mul(cur, cur);  //矩阵自乘
t>>=1;
}
return M[(1<<k)-1][(1<<k)-1];   //矩阵很特殊,只需要这一项。
}

int main()
{
//freopen("input.txt", "r", stdin);
while(~scanf("%d%d", &k, &n))    printf("%d\n", cal(n-1));
return 0;
}


AC代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: