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