朝奈池扔了$400$多个石头没出货啊啊啊啊啊
一个非常显然的$DP$:
设$f(i,j,k)$表示时间$i$到达$j$点,上一条经过的边为$k$。
一个非常显然的转移:
$f(i,j,k)\rightarrow f(i+1,edge(l).to,l)(l\neq k)$
用矩乘优化一波,但这样我们发现矩阵大小是$2nm$的,跑不动。
每个点的入边条数是有限的,所以很多状态是无用的,对每个点的所有入边在矩阵上开元素就行了。矩阵大小缩小到$2m$。
总复杂度$O((2m)^3\log t)$。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#define maxn 100005
#define inf 0x3f3f3f3f
const int mod = 45989;
using namespace std;
inline int read(){
int x=0,y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
int f[105][55][55],ma[55][65],id[55][65];
vector<int>e[55];
struct Matrix{
int a[130][130],l,c;
Matrix operator * (const Matrix &x){
Matrix ans;
ans.l=l,ans.c=x.c;
for(register int k=0;k<c;++k)
for(register int i=0;i<=l;++i)
for(register int j=0;j<x.c;++j)
ans.a[i][j]=(ans.a[i][j]+a[i][k]*x.a[k][j]%mod)%mod;
return ans;
}
Matrix operator ^ (int y){
Matrix ans=*this,x=ans;
--y;
while(y){
if(y&1)ans=ans*x;
x=x*x,y>>=1;
}
return ans;
}
Matrix(){memset(a,0,sizeof a);}
}tr,start;
int main(){
int n=read(),m=read(),L=read(),s=read()+1,t=read()+1,cnt=0;
while(m--){
int x=read()+1,y=read()+1;
e[x].push_back(y),e[y].push_back(x);
ma[x][e[x].size()-1]=e[y].size()-1;
ma[y][e[y].size()-1]=e[x].size()-1;
}
for(register int i=1;i<=n;++i)
for(register int j=0;j<e[i].size();++j)
id[i][j]=cnt++;
start.l=1,start.c=tr.l=tr.c=cnt;
for(register int i=1;i<=n;++i)
for(register int j=0;j<e[i].size();++j)
for(register int k=0;k<e[i].size();++k)
if(j!=k)++tr.a[id[i][j]][id[e[i][k]][ma[i][k]]];
for(register int i=0;i<e[s].size();++i)
++start.a[0][id[e[s][i]][ma[s][i]]];
start=start*(tr^(L-1));
int ans=0;
for(register int i=0;i<e[t].size();++i)(ans+=start.a[0][id[t][i]])%=mod;
printf("%d\n",ans);
}