vijos1603迷宫

这题的构思太巧妙了:

经典题目8 给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值
    把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j。令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)。类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数。同理,如果要求经过k步的路径数,我们只需要二分求出A^k即可。

代码:

 1 type matrix=array[1..55,1..55] of int64;
 2 var a,b:matrix;
 3     i,j,n,m,s,t,p:longint;
 4 function mo(x:int64):int64;
 5  begin
 6    mo:=x mod p;
 7  end;
 8 procedure init;
 9  begin
10    readln(n);
11    for i:=1 to n do
12     begin
13       for j:=1 to n do read(a[i,j]);
14       readln;
15     end;
16    fillchar(b,sizeof(b),0);
17    for i:=1 to n do b[i,i]:=1;
18    readln(m,s,t,p);
19  end;
20 procedure mul(var x,y,z:matrix);
21  var t:matrix;
22      i,j,k:longint;
23  begin
24    fillchar(t,sizeof(t),0);
25    for i:=1 to n do
26     for j:=1 to n do
27      for k:=1 to n do
28       t[i,j]:=mo(t[i,j]+x[i,k]*y[k,j]);
29    z:=t;
30  end;
31 procedure ksm(cs:longint);
32  begin
33    while cs<>0 do
34     begin
35       if cs and 1=1 then mul(a,b,b);
36       cs:=cs>>1;
37       mul(a,a,a);
38     end;
39  end;
40 procedure main;
41  begin
42    ksm(m);
43    writeln(b[s,t]);
44  end;
45 begin
46   init;
47   main;
48 end.     
View Code
原文地址:https://www.cnblogs.com/zyfzyf/p/3802370.html