P2579 [ZJOI2005]沼泽鳄鱼
显然可以列出 $dp$ 方程按时间转移
发现数据 $n$ 很小,$K$ 很大,考虑矩阵快速幂优化转移
但是不同时间的转移似乎不一样
发现题目中单个鱼的移动有周期性,显然整体的移动也有周期性,发现个体的周期只有 $2,3,4$
所以整体移动的周期最多也只有 $12$,所以考虑把 $12$ 步的转移一起考虑,最后剩下几步再暴力转
这样每 $12$ 步的转移都一样了
所以对于 $12$ 步一起的情况,直接把每一步的转移矩阵 $F[i],i \in [1,12]$ 乘在一起变成另一个转移矩阵 $G$ 做快速幂就好了
注意题目中点从 $0$ 标号,个人习惯从 $1$ 开始标号
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=57,mo=1e4; int n,m,S,T,K; inline int fk(int x) { return x>=mo ? x-mo : x; } struct Matrix { int a[N][N]; Matrix () { memset(a,0,sizeof(a)); } inline Matrix operator * (const Matrix &tmp) const { Matrix res; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) res.a[i][j]=fk(res.a[i][j]+a[i][k]*tmp.a[k][j]%mo); return res; } }Ans,F[N],G; Matrix ksm(Matrix X,int y) { Matrix res; for(int i=1;i<=n;i++) res.a[i][i]=1; while(y) { if(y&1) res=res*X; X=X*X; y>>=1; } return res; } int main() { n=read(),m=read(),S=read()+1,T=read()+1,K=read(); int a,b,tot,p[7]; for(int i=1;i<=m;i++) { a=read()+1,b=read()+1; F[0].a[a][b]=F[0].a[b][a]=1; } for(int i=1;i<=12;i++) F[i]=F[0]; tot=read(); for(int i=1;i<=tot;i++) { a=read(); for(int j=0;j<a;j++) p[j]=read()+1; for(int j=1;j<=12;j++) { int t=p[j%a]; for(int k=1;k<=n;k++) F[j].a[k][t]=0; } } G=F[1]; for(int i=2;i<=12;i++) G=G*F[i]; int t=K/12,s=K%12; Ans.a[1][S]=1; Ans=Ans*ksm(G,t); for(int i=1;i<=s;i++) Ans=Ans*F[i]; printf("%d\n",Ans.a[1][T]); return 0; }