您的位置:首页 > 其它

[vijos 1194]Domino(矩阵乘法)

2009-10-08 13:52 267 查看
【题目大意】:

n*m的棋盘,让你用1*2的骨牌完全覆盖,问有多少种方案。(m<=5,n<=10^9)

【题目分析】:

最开始我就往状压dp上想,但是发现这个n太大,不仅空间承受不了,时间也是不允许的。

想了很久,没有思路,所以决定去看看题解。

果然这个题有很神的算法。

标准算法:矩阵乘法。

我们将问题抽象化一下,在整个棋盘上,只有相邻两行有关联。这种想法类似状压dp。

这样一些状态之间就有转化关系。

这些状态通过一系列的转化,经过了n行,得到了1111……(满状态)

所以这个问题就转化成了:给你一个图,问从一个点出发经过n步正好回到原来的点的路径的个数。

这个就有一个经典的算法就是矩阵乘法。

将图的邻接矩阵进行乘方,矩阵的n次方得到的矩阵中[i,j]元素表示从i走到j经过正好n步的路径个数。

那么这个问题就很好解决了,方法就是找到状态之间的联系,得出矩阵。

然后快速幂乘方,得到矩阵的[1<<m-1,1<<m-1]元素即为所求。

编译通过...
测试数据 01:答案正确... 0ms
测试数据 02:答案正确... 0ms
测试数据 03:答案正确... 0ms
测试数据 04:答案正确... 0ms
测试数据 05:答案正确... 0ms
测试数据 06:答案正确... 0ms
测试数据 07:答案正确... 0ms
测试数据 08:答案正确... 0ms
测试数据 09:答案正确... 0ms
测试数据 10:答案正确... 0ms
测试数据 11:答案正确... 0ms
测试数据 12:答案正确... 0ms
测试数据 13:答案正确... 0ms
测试数据 14:答案正确... 0ms
测试数据 15:答案正确... 0ms
测试数据 16:答案正确... 0ms
测试数据 17:答案正确... 0ms
测试数据 18:答案正确... 0ms
测试数据 19:答案正确... 0ms
测试数据 20:答案正确... 0ms
测试数据 21:答案正确... 0ms
测试数据 22:答案正确... 0ms
测试数据 23:答案正确... 0ms
测试数据 24:答案正确... 0ms
测试数据 25:答案正确... 0ms
-------------------------
Accepted 有效得分:100 有效耗时:0ms

【代码】:

program vijos_1194;
type
matrix=array[0..32,0..32] of longint;
var
ans,g:matrix;
n,m,p,i,j,k:longint;
flag:boolean;
function multi(a,b:matrix):matrix;
var
ans:matrix;
i,j,k:longint;
begin
fillchar(ans,sizeof(ans),0);
for i:=0 to 1 shl m-1 do
for j:=0 to 1 shl m-1 do
for k:=0 to 1 shl m-1 do
ans[i,j]:=(ans[i,j]+a[i,k]*b[k,j]) mod p;
exit(ans);
end;
begin
assign(input,'a.in');
assign(output,'a.out');
reset(input); rewrite(output);
readln(n,m,p);
for i:=0 to 1 shl m-1 do
for j:=0 to 1 shl m-1 do
if (i or j=1 shl m-1) and ((i and j) in [0,3,6,12,15,24,27,30]) then
g[i,j]:=1;
flag:=false;
for i:=0 to (1 shl m-1) do ans[i,i]:=1;
while n>0 do
begin
if n mod 2=1 then ans:=multi(ans,g);
g:=multi(g,g);
n:=n div 2;
end;
writeln(ans[(1 shl m-1),(1 shl m-1)]);
close(input); close(output);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: