[SCOI2009]迷路(矩阵快速幂) 题解

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 。

 

结论:对于边权都相同的邻接矩阵$G$,$G^T$表示两点间长度为$T$的路径的方案数。

考虑矩阵乘法在这类题中的实际意义:

$a[i][j]=\sum b[i][k]*b[k][j]$     可以把k看作枚举的中继,就得到了更进一步的方案数

$(i->j)的方案数 = (i->k)的方案数 * (k->j)的方案数 \  (起点终点固定)$

 

自乘$n-1$次即可得到两点间长度为n的方案数。

虽然这道题带权,但可以注意到边权种类很少,完全可以在一条路上强行加点起到统一边权的效果。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=105,mod=2009;
struct matrix
{
    int a[N][N];
    matrix()
    {
        memset(a,0,sizeof(a));
    }
}g;
int n,T;
matrix operator * (matrix x,matrix y)
{
    matrix res;
    for(int i=0;i<n*9;i++)
        for(int j=0;j<n*9;j++)
            for(int k=0;k<n*9;k++)
                (res.a[i][j]+=x.a[i][k]*y.a[k][j])%=mod;
    return res;
}
matrix qpow(matrix a,int b)
{
    matrix res=a;
    while(b)
    {
        if(b&1)res=res*a;
        a=a*a;;
        b>>=1;
    }
    return res;
}
int main()
{
    scanf("%d%d",&n,&T);
    char s[N];
    for(int i=0;i<n;i++)
    {
        scanf("%s",s);
        for(int j=0;j<n;j++)
        {
            if(s[j]=='0')continue;
            int x=s[j]-'0';
            x--;
            g.a[i*9+x][j*9]=1;
        }
        for(int j=0;j<8;j++)
            g.a[i*9+j][i*9+j+1]=1;
    }
    matrix res=qpow(g,T-1);
    cout<<res.a[0][9*(n-1)]<<endl;
    return 0;
}

 

posted @ 2019-07-17 21:18  Rorschach_XR  阅读(293)  评论(0编辑  收藏  举报
//雪花飘落效果