Time Limit: 20 Sec
Memory Limit: 64 MB
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。
N ≤ 20,M ≤ 60,t ≤ 2^30,0 ≤ A,B
Output
一行,表示答案。
题目分析
不考虑 "不能走回头路"的限制
则可以用
d
p
[
i
]
[
u
]
dp[i][u]
dp[i][u]表示恰好在
i
i
i时刻走到
u
u
u的方案数
那么有转移方程
d
p
[
i
]
[
u
]
=
∑
d
p
[
i
−
1
]
[
v
]
dp[i][u]=\sum dp[i-1][v]
dp[i][u]=∑dp[i−1][v]其中v可以到达u
现在考虑如何排除回头路的影响
上述转移中前一步更新
d
p
[
i
−
1
]
[
v
]
dp[i-1][v]
dp[i−1][v]时
其实相当于在寻找所有指向v的边,而这里面显然包含了
u
→
v
u\rightarrow v
u→v
到更新
d
p
[
i
]
[
u
]
dp[i][u]
dp[i][u]这一步时,显然不能有
u
→
v
u\rightarrow v
u→v这条边参与
那么如何在保证
d
p
[
i
−
1
]
[
v
]
dp[i-1][v]
dp[i−1][v]正确的情况下令
d
p
[
i
]
[
u
]
dp[i][u]
dp[i][u]的更新没有
u
→
v
u\rightarrow v
u→v参与呢
我们把每条无向边拆成两条有向边
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示恰好在
i
i
i时刻走到
j
j
j指向的结点的方案数
在转移时只要剔除所有
j
j
j的反向边即可
满足线性递推的方程
用矩阵快速幂优化即可
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef long long lt;
lt read()
{
lt f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const lt mod=45989;
const int maxn=150;
int n,m,tim,s,t;
struct node{int v,nxt;}E[maxn];
int head[maxn],tot=1;
struct matrix
{
lt mat[maxn][maxn],row,col;
matrix(int r=0,int c=0){
row=r; col=c;
for(int i=1;i<=row;++i)
for(int j=1;j<=col;++j)
mat[i][j]=0;
}
};
matrix operator *(matrix a,matrix b){
matrix c=matrix(a.row,b.col);
for(int i=1;i<=a.row;++i)
for(int j=1;j<=b.col;++j)
for(int k=1;k<=a.col;++k)
{
c.mat[i][j]+=a.mat[i][k]*b.mat[k][j]%mod;
c.mat[i][j]%=mod;
}
return c;
}
matrix qpow(matrix a,lt k)
{
matrix res=matrix(a.row,a.col);
for(int i=1;i<=a.row;++i) res.mat[i][i]=1;
while(k){
if(k&1) res=res*a;
a=a*a; k>>=1;
}
return res;
}
void add(int u,int v)
{
E[++tot].nxt=head[u];
E[tot].v=v;
head[u]=tot;
}
int main()
{
n=read();m=read();tim=read();
s=read()+1;t=read()+1;
for(int i=1;i<=m;++i)
{
int u=read()+1,v=read()+1;
add(u,v); add(v,u);
}
matrix h=matrix(tot-1,tot-1);
for(int j=2;j<=tot;++j)
{
int u=E[j].v;
for(int i=head[u];i;i=E[i].nxt)
{
if((i^1)==j) continue;
h.mat[j-1][i-1]++;
}
}
matrix f=matrix(1,tot-1);
for(int i=head[s];i;i=E[i].nxt)
f.mat[1][i-1]++;
matrix res=f*qpow(h,tim-1);
lt ans=0;
for(int i=head[t];i;i=E[i].nxt)
ans=(ans+res.mat[1][(i^1)-1])%mod;
printf("%lld",ans);
return 0;
}