BZOJ 1898: [Zjoi2004]Swamp 沼泽鳄鱼(矩阵乘法)
可以发现,如果没有鳄鱼,那么就是裸地一道题,但是可以发现鳄鱼最多每12次重复,那么就少于12的那部分dp,其他的就矩阵乘法就行了
PS:第一次吧矩阵乘法AC了好开心QAQ
CODE:
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define mod 10000 #define maxn 60 using namespace std; struct mat{ int n,m,a[maxn][maxn]; mat(){n=m=0; memset (a,0, sizeof (a));} int I( int _x){n=m=_x; for ( int i=1;i<=n;i++) a[i][i]=1;} }; mat operator *( const mat &x, const mat &y){ mat ans; ans.n=x.n; ans.m=y.m; for ( int i=1;i<=ans.n;i++) for ( int j=1;j<=ans.m;j++) for ( int k=1;k<=x.m;k++){ ans.a[i][j]+=x.a[i][k]*y.a[k][j]; ans.a[i][j]%=mod; } return ans; } mat power(mat x, int y){ mat ans;ans.I(x.n); for (;y;y>>=1){ if (y&1) ans=ans*x; x=x*x; } return ans; } int n,m,s,e,fn,ti; bool b[60][60]; int a[20][7],t[60],f[60][60][15]; int main(){ scanf ( "%d%d%d%d%d" ,&n,&m,&s,&e,&ti); for ( int i=1;i<=m;i++) { int x,y; scanf ( "%d%d\n" ,&x,&y); x++;y++; b[x][y]=b[y][x]=1; } scanf ( "%d" ,&fn); for ( int i=1;i<=fn;i++) { scanf ( "%d" ,&t[i]); for ( int j=1;j<=t[i];j++) { scanf ( "%d" ,&a[i][j]);a[i][j]++; } } for ( int i=1;i<=n;i++) f[i][i][0]=1; for ( int i=1;i<=12;i++) for ( int j=1;j<=n;j++) for ( int k=1;k<=n;k++){ for ( int l=1;l<=n;l++) if (f[j][l][i-1]&&b[l][k]) (f[j][k][i]+=f[j][l][i-1])%=mod; for ( int l=1;l<=fn;l++) if (a[l][i%t[l]+1]==k) {f[j][k][i]=0;} } mat x,y; x.n=x.m=y.n=y.m=n; for ( int i=1;i<=n;i++) for ( int j=1;j<=n;j++) x.a[i][j]=f[i][j][12]; x=power(x,ti/12); for ( int i=1;i<=n;i++) for ( int j=1;j<=n;j++) y.a[i][j]=f[i][j][ti%12]; x=x*y; printf ( "%d" ,x.a[s+1][e+1]); return 0; } |