Solution
考虑dp,设计状态 f[i][j] 为当前从起点走了 i 步,到达 j 点
但要避免走上一条走过的路,所以还要记录上一条走过的路是哪一条
可以将 f[i][j] 改为表示当前从起点走了 i 步,在编号为 j 的有向路的终点
转移为f[i][j]=$\Sigma$f[i-1][k] (编号为 k 的有向路的终点是 j 的起点,且不是 j 的反边)
发现 t 过大,不过对于一个 j ,能转移到它的 k 是固定的
于是可以矩阵乘法
Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int N=51,M=121,P=45989;
int head[N],nxt[M],ver[M],tot;
int n,m,t,a,b,u,v,ans[M][M],pre[M][M],now[M][M];
void mul1()
{
memset(now,0,sizeof(now));
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
for(int k=1;k<=tot;k++)
now[i][j]+=ans[i][k]*pre[k][j]%P,now[i][j]%=P;
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
ans[i][j]=now[i][j];
}
void mul2()
{
memset(now,0,sizeof(now));
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
for(int k=1;k<=tot;k++)
now[i][j]+=pre[i][k]*pre[k][j]%P,now[i][j]%=P;
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
pre[i][j]=now[i][j];
}
void qpow(int y)
{
while(y)
{
if(y&1) mul1();
mul2(),y>>=1;
}
}
void add(int x,int y)
{
ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;
ver[++tot]=x,nxt[tot]=head[y],head[y]=tot;
}
int op(int x)
{
return x%2?x+1:x-1;
}
inline char get()
{
static char buf[1024];
static int pos=0,size=0;
if(pos==size)
{
size=fread(buf,1,1024,stdin);
pos=0;
if(!size) return EOF;
else return buf[pos++];
}
else return buf[pos++];
}
int read()
{
int sum=0,fh=1;
char ch=get();
while(!(ch>='0' && ch<='9'))
{
if(ch=='-') fh=-1;
ch=get();
}
while(ch>='0' && ch<='9' && ch!=EOF) sum=sum*10+ch-48,ch=get();
return sum*fh;
}
int main()
{
n=read(),m=read(),t=read(),a=read(),b=read();
for(int i=1;i<=m;i++)
{
u=read(),v=read();
add(u,v);
}
for(int j=1;j<=tot;j++)
for(int i=head[ver[op(j)]];i;i=nxt[i])
if(i!=j) pre[op(i)][j]++;
for(int i=head[a];i;i=nxt[i])
ans[1][i]++;
qpow(t-1);
int an=0;
for(int i=head[b];i;i=nxt[i])
an+=ans[1][op(i)],an%=P;
printf("%d\n",an);
return 0;
}
来源:https://www.cnblogs.com/hsez-cyx/p/12418191.html