题目大意:
一个$n(nle30)$个点$m(mle100)$条边的无向图,每次可以选择移动到相邻点、原地不动或原地自爆。一开始在编号为$1$的点,问$t(tle10^6)$秒后有多少种可能的行为方案?
思路:
新建结点编号$0$表示原地自爆,则在原图基础上对于每个点加上自环和通向$0$的有向边,用邻接矩阵$T$表示。用矩阵$F$记录方案数,其中$F_{0,i}$表示最后一步在$i$处的方案数,初始状态$F_{0,1}=1$。用矩阵快速幂算出$F'=F imes T^t$,答案即为$sum F'_{0,i}$。
1 #include<cstdio> 2 #include<cctype> 3 #include<cstring> 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int N=31,mod=2017; 12 int tmp[N][N]; 13 struct Matrix { 14 int n,m,val[N][N]; 15 void resize(const int &n,const int &m) { 16 this->n=n; 17 this->m=m; 18 } 19 Matrix &operator *= (const Matrix another) { 20 for(register int i=0;i<n;i++) { 21 for(register int j=0;j<another.m;j++) { 22 tmp[i][j]=0; 23 for(register int k=0;k<m;k++) { 24 (tmp[i][j]+=val[i][k]*another.val[k][j]%mod)%=mod; 25 } 26 } 27 } 28 memcpy(val,tmp,sizeof val); 29 return *this; 30 } 31 }; 32 Matrix f,t; 33 int main() { 34 const int n=getint(),m=getint(); 35 f.resize(1,n+1); 36 t.resize(n+1,n+1); 37 for(register int i=0;i<=n;i++) { 38 t.val[i][i]=t.val[i][0]=1; 39 } 40 for(register int i=0;i<m;i++) { 41 const int u=getint(),v=getint(); 42 t.val[u][v]=t.val[v][u]=1; 43 } 44 f.val[0][1]=1; 45 for(register int k=getint();k;k>>=1,t*=t) { 46 if(k&1) f*=t; 47 } 48 int ans=0; 49 for(register int i=0;i<=n;i++) { 50 (ans+=f.val[0][i])%=mod; 51 } 52 printf("%d ",ans); 53 return 0; 54 }