[矩阵乘法]JZOJ 2288 沼泽鳄鱼
分析
考试的时候总觉得这题在哪里见过……然后做法想好后才想起来是J爷的矩阵乘法习题
我们可以发现矩乘的过程其实是一个类似于floyd的过程,可以把一个点到另一个点的路径总长得出来,那么在边权为1的情况下就是方案数
然后一看K大也能大概猜出来是矩乘,可是不会打 菜哭了
因为鱼是有循环节的,我们可以把循环节的最小公倍数作为快速幂的基准
先处理出一个从1到12所有时间的情况都乘在一起的矩阵T
然后快速幂^k/12
最后再逐个乘上k%12的矩阵T即可
#include <iostream> #include <cstdio> #include <memory.h> using namespace std; typedef long long ll; const int N=60; const ll P=1e4; int n,fish,m,st,ed,K,fp[N][N]; bool use[N]; struct Rect { ll a[N][N]; ll *operator [](int i){return a[i];} void In() { for (int i=0;i<n;i++) a[i][i]=1; } void Empty() {memset(a,0,sizeof a);} Rect operator * (Rect b) { Rect c;c.Empty(); for (int i=0;i<n;i++) for (int j=0;j<n;j++) for (int k=0;k<n;k++) if (!use[k]) (c[i][j]+=a[i][k]*b[k][j]%P)%=P; return c; } }f,ans,e; Rect Ksm(Rect a,int y) { Rect ans; memset(use,0,sizeof use);ans.In(); while (y) { if (y&1) ans=ans*a; a=a*a; y>>=1; } return ans; } void Pre_Process(int x) { memset(use,0,sizeof use); for (int i=1;i<=fish;i++) use[fp[i][(x-1)%fp[i][0]+1]]=1; } int main() { scanf("%d%d%d%d%d",&n,&m,&st,&ed,&K);e.In();ans.In(); for (int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),f[u][v]++,f[v][u]++; scanf("%d",&fish); for (int i=1;i<=fish;i++) { scanf("%d",&fp[i][0]); for (int j=1;j<=fp[i][0];j++) scanf("%d",&fp[i][j]); } for (int i=1;i<=12;i++) Pre_Process(i),e=e*f; ans=ans*Ksm(e,K/12); for (int i=1;i<=K%12;i++) Pre_Process(i),ans=ans*f; printf("%lld",ans.a[st][ed]); }
在日渐沉没的世界里,我发现了你。