BZOJ1875:[SDOI2009]HH去散步
Description
HH有个一成不变的习惯,喜欢饭后百步走。所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离。 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人,所以他每天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法。 现在给你学校的地图(假设每条路的长度都是一样的都是1),问长度为t,从给定地 点A走到给定地点B共有多少条符合条件的路径
Input
第一行:五个整数N,M,t,A,B。其中N表示学校里的路口的个数,M表示学校里的 路的条数,t表示HH想要散步的距离,A表示散步的出发点,而B则表示散步的终点。 接下来M行,每行一组Ai,Bi,表示从路口Ai到路口Bi有一条路。数据保证Ai = Bi,但 不保证任意两个路口之间至多只有一条路相连接。 路口编号从0到N − 1。 同一行内所有数据均由一个空格隔开,行首行尾没有多余空格。没有多余空行。 答案模45989。
Output
一行,表示答案。
Sample Input
4 5 3 0 0
0 1
0 2
0 3
2 1
3 2
0 1
0 2
0 3
2 1
3 2
Sample Output
4
HINT
对于30%的数据,N ≤ 4,M ≤ 10,t ≤ 10。 对于100%的数据,N ≤ 20,M ≤ 60,t ≤ 2^30,0 ≤ A,B
题解:
看数据范围就知道是矩阵快速幂了。
因为不能立刻原路返回,所以不能单纯以位置作为矩阵的行。考虑将一条边拆为两个点,表示通过这条边从Ai走到Bi与从Bi走到Ai的情况(显然这两个状态不能互相到达)。以这些点加上起点作为矩阵的状态,然后在其之间构造转移方式,就得到了转移矩阵。求完快速幂后,把所有以终点作为到达点的状态方案数相加,即为答案。
代码:
1 const 2 mo=45989; 3 var 4 i,j,k,l,n,m,t,s,e,ss,ee,cnt:longint; 5 a:array[1..2,0..121,0..121]of longint; 6 c:array[0..121,0..121]of longint; 7 tt:array[0..121,1..2]of longint; 8 ans:longint; 9 procedure qq(z,x,y:longint); 10 var i,j,k:longint; 11 begin 12 for i:=1 to cnt do 13 for j:=1 to cnt do 14 begin 15 c[i,j]:=0; 16 for k:=1 to cnt do c[i,j]:=(c[i,j]+a[x,i,k]*a[y,k,j])mod mo; 17 end; 18 for i:=1 to cnt do 19 for j:=1 to cnt do a[z,i,j]:=c[i,j]; 20 end; 21 procedure ksm(t:longint); 22 begin 23 while t>0 do 24 begin 25 if t mod 2=1 then qq(1,1,2); 26 t:=t div 2; qq(2,2,2); 27 end; 28 end; 29 begin 30 readln(n,m,t,s,e); cnt:=1; inc(s); inc(e); 31 for i:=1 to m do 32 begin 33 readln(j,k); inc(j); inc(k); 34 inc(cnt); tt[cnt,1]:=j; tt[cnt,2]:=k; 35 inc(cnt); tt[cnt,1]:=k; tt[cnt,2]:=j; 36 end; 37 for i:=2 to cnt do if tt[i,1]=s then a[2,1,i]:=1; 38 for i:=2 to cnt do 39 begin 40 for j:=2 to cnt do 41 if(tt[j,1]=tt[i,2])and(i xor 1<>j)then inc(a[2,i,j]); 42 end; 43 a[1,1,1]:=1; 44 ksm(t); 45 for i:=2 to cnt do if tt[i,2]=e then ans:=(ans+a[1,1,i])mod mo; 46 writeln(ans); 47 end.