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
Day1
一眼矩乘。
但是具体怎么转移没想到,只有dp推。。结果xjb乱推推过了。。正确解法应该是遍历图然后看两个点之间是否联通然后矩阵乘法。判断i==j^1其实就是看i是不是j的反向边。。如果打过边双应该就很熟悉了,常常用。
代码比较丑。。
#include<cstdio>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int mo=45989, maxe=122;
struct arr{int c[maxe][maxe];};
int n,m,t,a,b,i,j,k,cal[maxe];
int tot,go[maxe],bz[maxe],next[maxe],f1[25];
arr c,ans,ct;
void ins(int x,int y)
{
go[++tot]=y;
bz[tot]=i;
next[tot]=f1[x];
f1[x]=tot;
}
arr mul(arr a, arr b)
{
memset(ct.c,0,sizeof(ct.c));
fo(i,0,tot)
fo(j,0,tot)
fo(k,0,tot) ct.c[i][j]=(ct.c[i][j]+a.c[i][k]*b.c[k][j])%mo;
return ct;
}
void mi(int y)
{
while (y)
{
if (y&1) ans=mul(ans,c);
c=mul(c,c);
y>>=1;
}
}
int main()
{
scanf("%d %d %d %d %d\n",&n,&m,&t,&a,&b);
tot=-1;
ins(n,a);
fo(i,1,m)
{
scanf("%d%d",&j,&k);
ins(j,k), ins(k,j);
}
fo(i,0,tot)
{
int p=f1[go[i]];
while (p)
{
if (bz[p]!=bz[i]) c.c[i][p]=1;
p=next[p];
}
if (go[i]==b) cal[++cal[0]]=i;
}
ans.c[1][0]=1;
mi(t);
fo(i,1,cal[0]) ans.c[1][0]=(ans.c[1][0]+ans.c[1][cal[i]])%mo;
printf("%d\n",ans.c[1][0]);
}