zoukankan      html  css  js  c++  java
  • bzoj1297: [SCOI2009]迷路

    矩阵。

    一个图的邻接矩阵的m次幂相当于 长度恰好为m的路径数。这要求边权为1。

    因为边权小于等于9,所以可以把一个点拆成9的点。 拆成的第(i+1)个点向第i个点连边。

    如果存在边(u,v,w) 就由u点向v拆成的第w个点连边,这样表明w次以后就可以到达v点。

    这个拆点很牛啊,不过第一眼连邻接矩阵都没看出来。。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn = 100 + 10;
    const int mod = 2009; 
    
    struct Matrix {
        int a[maxn][maxn];
        int n;
        
        int* operator [] (int x) {
            return a[x];    
        }
        
        Matrix operator* (Matrix b) {
            Matrix c;
            c.n=n;
            for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                c[i][k]=(c[i][k]+a[i][j]*b[j][k])%mod;    
            return c;
        }
        
        Matrix operator^ (int e) {
            Matrix res,tmp=*this;
            res.init(n);
            while(e) {
                if(e&1) res=res*tmp;
                tmp=tmp*tmp;
                e>>=1;    
            }
            return res;
        }
        
        void output() {
            for(int i=1;i<=n;i++) {            
                for(int j=1;j<=n;j++)
                    printf("%d ",a[i][j]);
                printf("
    ");        
            }
        }
        
        void input() {
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++) 
                scanf("%d",&a[i][j]);
        }
        
        void init(int k) {
            n=k;
            for(int i=1;i<=n;i++) a[i][i]=1;    
        }
        
        Matrix() {
            memset(a,0,sizeof(a));    
        }
    }g,res;
    
    int n,m,k,vid;
    int id[maxn][maxn];
    
    int main() {
        scanf("%d%d",&n,&m); 
        k=n*9; res.n=g.n=k; 
        for(int i=1;i<=n;i++)
        for(int j=1;j<=9;j++) 
            id[i][j]=++vid;
        
        for(int i=1;i<=n;i++)
        for(int j=1;j<9;j++)
            g[id[i][j+1]][id[i][j]]=1;
        
        
        for(int i=1,t;i<=n;i++)
        for(int j=1;j<=n;j++) {
            scanf("%1d",&t);
            if(!t) continue;
            g[id[i][1]][id[j][t]]=1;
        }    
        for(int i=1;i<=k;i++) res[i][i]=1;
        res=res*(g^m);
        printf("%d
    ",res[id[1][1]][id[n][1]]);
        return 0;    
    }
  • 相关阅读:
    Codeforces932E. Team Work
    BZOJ2956: 模积和
    Codeforces932D. Tree
    51nod1040 最大公约数之和
    伯努利数
    BZOJ3456: 城市规划
    BZOJ4555: [Tjoi2016&Heoi2016]求和
    Codeforces936C. Lock Puzzle
    BZOJ3771: Triple
    SPOJ LCS2 后缀自动机
  • 原文地址:https://www.cnblogs.com/invoid/p/5634926.html
Copyright © 2011-2022 走看看