zoukankan      html  css  js  c++  java
  • BZOJ1297 迷路

    传送门

    题目大意:

    输入n(点的数量),t(时间),和一个n*n的矩阵,第i行第j列表示第i个节点到第j个节点有一条matrix[i]j时间的边,若为0则没有边,问从1到n恰好经过t时间的方案数有多少种?

    题目分析:

    矩阵的幂与路径的联系:若i到j有一条边权为1的边,那么matrix[i][j]=1,(matrix^k)中的[1][n]即代表1到n距离恰好k的方案数(同样也可以表示:i到j有一条边,1到n的经过边数恰好为k的方案数。)
    这道题目简化后是:知道i到j有边权为1的边,求x到y的距离为k的方案总数,正是上面提到的。
    加上边权后不能套用上边直接求解,因为上面的做法只针对权值为1。但由于一条边的权值只从0~9,那么可以将一个点拆成9个点,若i到j有一条边权为k的边,就相当于从i拆出的第k个节点向j拆出的第1个点连边,i拆出的点之间连边权为1的边,这样(matrix^t)的[getkth(i, 1)][getkth(n, 1)]即表示方案数。(getkth表示i拆出的第j个点)

    code

    #include<bits/stdc++.h>
    using namespace std;
    
    namespace IO{
        inline int read(){
            int i = 0, f = 1; char ch = getchar();
            for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
            if(ch == '-') f = -1, ch = getchar();
            for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
            return i * f;
        }
        inline void wr(int x){
            if(x < 0) putchar('-'), x = -x;
            if(x > 9) wr(x / 10);
            putchar(x % 10 + '0');
        }
    }using namespace IO;
    
    const int N = 15, Mod = 2009;
    int n, T;
    struct node{
        int b[N*10][N*10]; //每个点拆成9个
        node(){}
        inline void init(){
            memset(b, 0, sizeof b);
        }
        inline void set(int p, int q, int z){b[p][q] = z;}
        inline void I(){
            //初始化为单位矩阵
            memset(b, 0, sizeof b);
            for(int i = 1; i <= n*9; i++)
                set(i, i, 1);
        }
        inline node operator * (const node &p) const{
            node ret;
            for(int i = 1; i <= n*9; i++)
                for(int j = 1; j <= n*9; j++){
                    int sum = 0;
                    for(int k = 1; k <= n*9; k++) sum = (sum + b[i][k] * p.b[k][j]) % Mod;
                    ret.set(i, j, sum);
                }
            return ret;
        }
        inline node operator ^ (int tt){
            node ret; ret.I();
            node tmp = *this;
            for(; tt; tt >>= 1, tmp = tmp * tmp) if(tt & 1) ret = ret * tmp;
            return ret;
        }
    }matrix, ret;
    
    inline int getkth(int x, int k){
        return (x-1) * 9 + k;
    }
    
    int main(){
        n = read(), T = read();
        matrix.init(), ret.init();
        for(int i = 1; i <= n; i++) 
            for(int j = 1; j <= 8; j++){
                matrix.set(getkth(i, j), getkth(i, j + 1), 1);
            }
        for(int i = 1; i <= n; i++){
            char c[N]; scanf("%s", c + 1);
            for(int j = 1; j <= n; j++){
                int x = c[j] - '0';
                if(x) matrix.set(getkth(i, x), getkth(j, 1), 1); 
            }
        }
        ret = matrix ^ T;
        wr(ret.b[getkth(1, 1)][getkth(n, 1)]);
        return 0;
    }
    
    
  • 相关阅读:
    Java 访问权限字节码
    vscode 写js项目,自动按照eslint保存
    mac 按键符号说明
    下载git单个文件或目录
    生成密码的方式
    git 笔记
    后端数据返回的snake_case格式,但前端的规范为驼峰格式,实现一种snake_case转驼峰的方法
    wireshark 数据协议解析
    MAC App破解之路十一 charles
    生成检查的顺子的表
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7695591.html
Copyright © 2011-2022 走看看