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.