Bzoj1875 [SDOI2009]HH去散步
Submit: 1518 Solved: 727
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
Source
数学问题 矩阵乘法
矩阵乘法可以用来求图上两点之间的路径数。
因为题目限制了不能走刚走过的路,所以用点到点的度数矩阵无法统计答案。
↑那么就改成统计边到边的转移方式。即从一条边走到另一条边的方案数。虚拟一个结点表示“起点所连的边(的集合)”,从该点只能出不能回。
处理出度数矩阵以后,自乘t-1次(最后一步要走到B)。
然后扫描从哪些边可以一步走到B,累加答案即可
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int mod=45989; 10 const int mxn=210; 11 int read(){ 12 int x=0,f=1;char ch=getchar(); 13 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 struct edge{ 18 int v,nxt; 19 }e[mxn<<2]; 20 int hd[mxn],mct=0; 21 void add_edge(int u,int v){ 22 e[mct].nxt=hd[u];e[mct].v=v;hd[u]=mct;mct++;return; 23 } 24 int n,m,t,A,B; 25 struct Mat{ 26 int a[mxn][mxn]; 27 void clear(){memset(a,0,sizeof a);return;} 28 Mat operator * (Mat c){ 29 Mat res;memset(res.a,0,sizeof res.a); 30 for(int i=0;i<=mct;i++) 31 for(int j=0;j<=mct;j++) 32 for(int k=0;k<=mct;k++){ 33 (res.a[i][j]+=a[i][k]*c.a[k][j])%=mod; 34 } 35 return res; 36 } 37 }mp,s; 38 Mat MatMul(Mat M,int k){ 39 Mat tmp;tmp.clear(); 40 for(int i=0;i<=mct;i++)tmp.a[i][i]=1; 41 while(k){ 42 if(k&1)tmp=tmp*M; 43 M=M*M; 44 k>>=1; 45 } 46 return tmp; 47 } 48 int main(){ 49 int i,j,u,v; 50 n=read();m=read();t=read();A=read();B=read(); 51 memset(hd,-1,sizeof hd); 52 for(i=1;i<=m;i++){ 53 u=read();v=read(); 54 add_edge(u,v); 55 add_edge(v,u); 56 } 57 for(i=hd[A];i>=0;i=e[i].nxt) s.a[mct][i]++; 58 for(i=0;i<mct;i++){ 59 for(j=hd[e[i].v];j>=0;j=e[j].nxt){ 60 if(j==(i^1))continue; 61 mp.a[i][j]++; 62 } 63 } 64 /* 65 for(i=0;i<=mct;i++){ 66 for(j=0;j<=mct;j++){ 67 printf("%d ",mp.a[i][j]); 68 } 69 printf("\n"); 70 } 71 */ 72 mp=MatMul(mp,t-1); 73 s=s*mp; 74 int ans=0; 75 for(i=hd[B];i>=0;i=e[i].nxt){ 76 ans=(ans+s.a[mct][i^1])%mod; 77 } 78 printf("%d\n",ans); 79 return 0; 80 }
本文为博主原创文章,转载请注明出处。