sdoi 2009 HH去散步 矩阵乘
如果没有题里的“不会立刻沿着刚刚走来的路走回”限制,那么直接矩乘计算k步的方案数
但加了这个限制,就不能以点来矩乘了,考虑边数<=60,如果以边建邻接矩阵呢??
先拆边,再把每一个边和以其终点为起点的边相连,注意不能是拆前的同一条边。
然后矩阵乘喽。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define mod 45989 using namespace std; int a[122][122],b[122],c[122][122],d[122]; int ans,n,m,t,S,T; bool bo; int e=1,head[22]; struct edge{ int u,v,next; }ed[122]; void add(int u,int v){ ed[e].u=u; ed[e].v=v; ed[e].next=head[u]; head[u]=e++; } void work(int A[122][122],int B[122][122],int C[122][122]){ int D[122][122]; for(int i=1;i<=2*m;i++) for(int j=1;j<=2*m;j++){ D[i][j]=0; for(int k=1;k<=2*m;k++) D[i][j]=(D[i][j]+(A[i][k]*B[k][j])%mod)%mod; } for(int i=1;i<=2*m;i++) for(int j=1;j<=2*m;j++) C[i][j]=D[i][j]; } int main() { int u,v; scanf("%d%d%d%d%d",&n,&m,&t,&S,&T); S++; T++; for(int i=1;i<=m;i++){ scanf("%d%d",&u,&v); u++; v++; add(u,v); add(v,u); } for(int i=1;i<=2*m;i++) for(int j=1;j<=2*m;j++){ if(ed[i].v==ed[j].u) a[i][j]=1; } for(int i=1;i<=2*m;i+=2) a[i][i+1]=a[i+1][i]=0; for(int i=1;i<=2*m;i++) c[i][i]=1; for(int i=head[S];i;i=ed[i].next) b[i]=1; t--; while(t){ if(t&1) work(a,c,c); work(a,a,a); t>>=1; } for(int i=1;i<=2*m;i++) for(int j=1;j<=2*m;j++) d[i]=(d[i]+(b[j]*c[j][i])%mod)%mod; for(int i=1;i<=2*m;i++) if(ed[i].v==T) ans=(ans+d[i])%mod; printf("%d\n",ans); return 0; }
人生如梦亦如幻 朝如晨露暮如霞。