Bzoj1875 [SDOI2009]HH去散步

Time Limit: 20 Sec  Memory Limit: 64 MB
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

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("
");
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
",ans);
79     return 0;
80 }
本文为博主原创文章,转载请注明出处。
原文地址:https://www.cnblogs.com/SilverNebula/p/6506652.html