#jZCybttg060507. 1647:迷路

1647:迷路

1647:迷路

题目描述

Windy 在有向图中迷路了。该有向图有 NN 个节点,Windy 从节点 00 出发,他必须恰好在 TT 时刻到达节点 N1N-1

现在给出该有向图,你能告诉 Windy 总共有多少种不同的路径吗?

注意:Windy 不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

输入格式

第一行包含两个整数 N,TN, T

接下来有 NN 行,每行一个长度为 NN 的字符串。第 ii 行第 jj 列为 0 表示从节点 ii 到节点 jj 没有边,为 19 表示从节点 ii 到节点 jj 需要耗费的时间。

输出格式

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

样例

样例输入 #1

2 2
11
00

样例输出 #1

1

样例解释 #1

  • N=2N=2,节点编号 0011,Windy 从 00 出发,恰好在 T=2T=2 时刻到达节点 11
  • 邻接矩阵:
    • 第一行:11 表示从节点 0000 有边,耗时 11;从节点 0011 有边,耗时 11
    • 第二行:00 表示从节点 110011 都没有边。
  • 要求 T=2T=2,从 0011 的路径:
    • 0010 \to 0 \to 1:时间 1+1=21+1=2,符合。
    • 010 \to 1:时间 11,不符合 T=2T=2
  • 只有 11 种路径,输出 11

样例输入 #2

5 30
12045
07105
47805
12024
12345

样例输出 #2

852

数据范围

  • 对于 30%30\% 的数据,满足 2N5,1T302 \le N \le 5, 1 \le T \le 30
  • 对于 100%100\% 的数据,满足 2N10,1T1092 \le N \le 10, 1 \le T \le 10^9

时空限制

  • 时间限制:1000 ms
  • 内存限制:524288 KB

注意:本题是有向图路径计数问题,但边权可能为 1199(不为 00),且 TT 很大。由于 NN 很小(最多 1010),但 TT 可达 10910^9,需要使用矩阵快速幂加速。然而边权不是 11,不能直接使用邻接矩阵的 TT 次幂。

常用技巧:将每个节点拆成多个状态,表示在某个时间余数下的位置。因为边权最大为 99,我们可以将每个节点 uu 拆成 99 个状态:(u,0),(u,1),,(u,8)(u, 0), (u, 1), \dots, (u, 8),其中 (u,k)(u, k) 表示当前在节点 uu,且已经走了 kk 个单位时间(即还需要等待 ?? 才能完成当前边的剩余时间?)。更常用的方法是:将原图转换为边权为 11 的新图,然后对新图做矩阵快速幂。

具体拆点方法:

  • 对于原图中一条从 uuvv 的边,权值为 ww,我们将其转换为一条路径:从 uu 出发,经过 w1w-1 个中间状态,最后到达 vv。即:uu1u2uw1vu \to u_1 \to u_2 \to \dots \to u_{w-1} \to v,其中 u1,u2,,uw1u_1, u_2, \dots, u_{w-1} 是新添加的节点,每条边权值为 11
  • 但这样添加的节点数可能很多(最多 N×9N \times 9)。由于 N10N \le 10,边权最大 99,所以每个节点最多拆成 99 个状态,总节点数不超过 N×9=90N \times 9 = 90。矩阵大小 90×9090 \times 90,矩阵快速幂 O(903logT)O(90^3 \log T),计算量约为 90372900090^3 \approx 729000,乘以 logT30\log T \approx 30,约 2×1072 \times 10^7,可以接受。

更简洁的拆点方法(经典):

  • 对每个节点 uu,我们创建 99 个状态:u0,u1,,u8u_0, u_1, \dots, u_8,其中 u0u_0 表示实际节点 uu(即已经完成一条边,可以开始新边的状态)。对于边权 ww 的边 uvu \to v,我们连接 u0vw1u_0 \to v_{w-1}(因为从 uu 出发,需要 ww 个单位时间到达 vv,所以先到达 vw1v_{w-1},然后经过 w1w-1 步逐步变成 v0v_0)。同时,对于每个 k1k \ge 1,有 ukuk1u_k \to u_{k-1} 的边(权值为 11),表示时间的流逝。
  • 这样,新图中所有边的权值都是 11,邻接矩阵 AA 表示一步转移(单位时间)的可达性。那么 ATA^T 中的 (00,(N1)0)(0_0, (N-1)_0) 元素就是从起点 000_0 到终点 (N1)0(N-1)_0 恰好 TT 步的路径数。

具体构造:

  • 新图节点编号:对于原节点 ii,其对应的 99 个状态编号为 $i \times 9 + 0, i \times 9 + 1, \dots, i \times 9 + 8$。通常 i0i_0 对应 i×9i \times 9
  • 对于每个原节点 ii,对于 k=1k = 188,添加边 (i×9+k,i×9+k1)(i \times 9 + k, i \times 9 + k - 1),表示时间流逝(即状态 iki_k 经过 11 单位时间变为 ik1i_{k-1})。
  • 对于原图中从 iijj 的边,权值为 ww1w91 \le w \le 9),添加边 (i×9,j×9+w1)(i \times 9, j \times 9 + w - 1),表示从 i0i_0 出发,经过 11 单位时间到达 jw1j_{w-1}(然后通过时间流逝边逐步变成 j0j_0)。

这样,新图的节点数为 N×9N \times 9,边权均为 11,邻接矩阵 AA0/10/1 矩阵。然后计算 ATA^T,取 (start,end)(start, end) 元素即可,其中 start=0×9=0start = 0 \times 9 = 0end=(N1)×9end = (N-1) \times 9

注意:如果 T=0T=0,需要特判:当 0=N10 = N-1 时路径数为 11,否则为 00。但题目 T1T \ge 1,且 N2N \ge 2,起点和终点不同,所以 T=0T=0 不可能到达(除非起点等于终点,但题目起点 00,终点 N1N-1,如果 N=1N=10=N10=N-1,但 N2N \ge 2,所以不考虑)。

算法步骤:

  1. 读入 N,TN, T 和邻接矩阵(字符串)。
  2. 新图节点数 tot=N×9tot = N \times 9,初始化 tot×tottot \times tot 的矩阵 AA00
  3. 对于每个原节点 ii0i<N0 \le i < N):
    • 对于 k=1k = 188,令 A[i×9+k][i×9+k1]=1A[i \times 9 + k][i \times 9 + k - 1] = 1
  4. 对于每个原节点 iijj,如果原图中 iijj 的边权 w=str[i][j]0w = str[i][j] - '0',且 w>0w > 0,则令 A[i×9][j×9+w1]=1A[i \times 9][j \times 9 + w - 1] = 1
  5. 计算 B=ATB = A^T(矩阵快速幂,模 20092009)。
  6. 输出 B[0][(N1)×9]B[0][(N-1) \times 9](即从起点 000_0 到终点 (N1)0(N-1)_0 的路径数)。

注意模数 20092009 不是质数,但矩阵乘法只需取模即可。

由于 tot90tot \le 90,矩阵乘法 O(tot3)O(tot^3) 稍大,但 903=72900090^3=729000,快速幂 logT30\log T \le 30,总计算量约 2×1072 \times 10^7,在 1 秒内可能较紧,但可以使用一些优化(如循环展开、使用 int 等)。由于 N10N \le 10tot90tot \le 90,实际可能更小。

另一种优化:注意到矩阵 AA 是稀疏的,但快速幂需要稠密矩阵乘法。不过 9090 的规模可以接受。