bzoj1875: [SDOI2009]HH去散步
矩阵乘法。
关于点的无法表示刚才走过的路不能走,所以用把边拆成俩个来建图,自己不能和自己连。
然后再用俩点表示起点和终点。
快速幂求矩阵(t+1)次就可以了(t+1次是因为到达终点那条边就需要t次,然后新建了一个终点,就会多走一步)。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 200; const int maxm = 200; const int mod = 45989; int u[maxm],v[maxm],next[maxm],eid; int n,m,t,p1,p2; void addedge(int a,int b) { u[eid]=a; v[eid]=b; eid++;//next[eid]=g[a]; g[a]=eid++; u[eid]=b; v[eid]=a; eid++;//next[eid]=g[b]; g[b]=eid++; } struct Matrix { int a[maxm][maxm]; int* operator [] (int x) { return a[x]; } Matrix operator * (Matrix b) { Matrix res; for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=0;k<=n;k++) res[i][k]=(res[i][k]+a[i][j]*b[j][k])%mod; return res; } Matrix operator ^ (int e) { Matrix res,tmp=*this; res.init(); while(e) { if(e&1) res=res*tmp; tmp=tmp*tmp; e>>=1; } return res; } void init() { memset(a,0,sizeof(a)); for(int i=0;i<=n;i++) a[i][i]=1; } void debug() { for(int i=0;i<=n;i++) { for(int j=0;j<=n;j++) printf("%d ",a[i][j]); printf("\n"); } } Matrix() { memset(a,0,sizeof(a)); } }s; int main() { scanf("%d%d%d%d%d",&n,&m,&t,&p1,&p2); for(int i=1,u,v;i<=m;i++) { scanf("%d%d",&u,&v); addedge(u,v); } for(int i=0;i<eid;i++) for(int j=0;j<eid;j++) if(v[i]==u[j]&& (i!=(j^1))) { s[i][j]=1; } for(int i=0;i<eid;i++) { if(u[i]==p1) s[eid][i]=1; if(v[i]==p2) s[i][eid+1]=1; } n=eid+1; s=s^(t+1); printf("%d\n",s[eid][eid+1]); return 0; }