zoukankan      html  css  js  c++  java
  • 【矩阵快速幂】bzoj1297 [SCOI2009]迷路

    1297: [SCOI2009]迷路

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 1407  Solved: 1007
    [Submit][Status][Discuss]

    Description

    windy在有向图中迷路了。 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

    Input

    第一行包含两个整数,N T。 接下来有 N 行,每行一个长度为 N 的字符串。 第i行第j列为'0'表示从节点i到节点j没有边。 为'1'到'9'表示从节点i到节点j需要耗费的时间。

    Output

    包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以2009的余数。

    Sample Input

    【输入样例一】
    2 2
    11
    00

    【输入样例二】
    5 30
    12045
    07105
    47805
    12024
    12345


    Sample Output

    【输出样例一】
    1

    【样例解释一】
    0->0->1

    【输出样例二】
    852

    HINT

    30%的数据,满足 2 <= N <= 5 ; 1 <= T <= 30 。 100%的数据,满足 2 <= N <= 10 ; 1 <= T <= 1000000000 。

    题解

    首先我们看到T的范围辣么大

    再一看求1到n长度为k的路径

    这不是明显的矩阵快速幂嘛!

    但是问题来了

    矩阵快速幂只适用于1的情况,题中边权却不一定为1

    这时我们又看到边权属于1到9

    那么拆点不就好了么~

    把点i拆成i1~i9,然后把每个ii到ii+1连边,边权为1

    然后如果i到j有长为x的边,就在ix和j1中间连一条边权为1的边

    然后就跑矩阵快速幂就好~

    复杂度O((10*n)3*log t)

    代码

    //by 减维
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<cstdlib>
    #include<ctime>
    #include<cmath>
    #include<map>
    #include<bitset>
    #include<algorithm>
    #define ll long long
    #define p 2009
    using namespace std;
    
    struct matrix{
        int a[105][105];
    }b,c;
    
    char a[15];
    int n;
    ll t;
    
    matrix operator * (const matrix&x,const matrix&y)
    {
        matrix z;
        for(int i=0;i<=104;++i)
            for(int j=0;j<=104;++j)
                z.a[i][j]=0;
        for(int i=1;i<=n*10;++i)
            for(int j=1;j<=n*10;++j)
                for(int k=1;k<=n*10;++k)
                    z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%p)%p;
        return z;
    }
    
    int main()
    {
        scanf("%d%lld",&n,&t);
        for(int i=1;i<=n;++i)
            for(int j=1;j<10;++j)
                b.a[(i-1)*10+j][(i-1)*10+j+1]=1;
        for(int i=1;i<=10*n;++i)c.a[i][i]=1;
        for(int i=1;i<=n;++i)
        {
            scanf("%s",a+1);
            for(int j=1;j<=n;++j)
                if(a[j]>'0')b.a[(i-1)*10+a[j]-'0'][(j-1)*10+1]=1;
        }
        while(t)
        {
            if(t&1)c=b*c;
            b=b*b;
            t>>=1;
        }
        printf("%d",c.a[1][(n-1)*10+1]);
    }
  • 相关阅读:
    Flask 入门
    Android studio 混淆打包
    Android----获取包名和sh1
    windows下 安装 rabbitMQ 及操作常用命令
    Nginx
    Linux安装mongoDB步骤和方法
    史上最简单的 SpringCloud 教程 | 终章
    idea 项目热部署设置
    JDK源码阅读顺序
    Linux常用命令
  • 原文地址:https://www.cnblogs.com/rir1715/p/7747972.html
Copyright © 2011-2022 走看看