Luogu P4159 [SCOI2009]迷路 矩阵快速幂+精巧转化
大致就是矩阵快速幂吧。。
这个时候会发现这些边权$\le 9$,然后瞬间想到上回一道题:是不是可以建一堆转移矩阵再建一个$lcm(1,2,3,4,5,6,7,8,9)$的矩阵?。。。后来发现十分的慢qwq也好像不对
于是考虑转化一下:首先把点$u$建成九个点,$P(u,i)$表示$u$点的第$i$个子点(其实就是计算编号用的).
先初始化,把所有u的点依次连上边权为1的边
然后比如有一条$(u,v)=x$的边,我们就把$P(u,x)与P(v,1)$连边(是不是十分精妙)
然后快速幂,搞定!
#include<cstdio> #include<iostream> #include<cstring> const int N=128,M=2009; #define R register int #define P(i,j) (9*(i-1)+j) using namespace std; struct Mat { int sz,m[N][N]; inline void clear() {memset(m,0,sizeof(m));} inline Mat() {clear(); sz=0;} inline Mat operator * (const Mat& x)const { register Mat ret; ret.sz=sz; for(R i=1;i<=sz;++i) for(R k=1;k<=sz;++k) for(R j=1;j<=sz;++j) (ret.m[i][j]+=m[i][k]*x.m[k][j]%M)%=M; return ret; } inline void operator *= (const Mat& x) {*this=(*this)*x;} inline void e() {clear(); for(R i=1;i<=sz;++i) m[i][i]=1;} inline Mat operator ^ (int b) { register Mat ret,a=(*this); ret.sz=sz; ret.e(); for(;b;b>>=1,a*=a) if(b&1) ret*=a; return ret; } }a; int n,k; signed main() { scanf("%d%d",&n,&k); R n0=n; n*=9; a.sz=n; for(R i=1;i<=n0;++i) for(R j=1;j<=8;++j) a.m[P(i,j)][P(i,j+1)]=1; for(R i=1;i<=n0;++i) for(R j=1;j<=n0;++j) { R x; scanf("%1d",&x); if(x>0) a.m[P(i,x)][P(j,1)]=1; } a=a^k; printf("%d",a.m[1][P(n0,1)]); }
2019.05.25