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

上一篇:P2657 [SCOI2009]windy数


下一篇:Mysql事务与锁原理