[Luogu P4159] [BZOJ 1297] [SCOI2009]迷路

洛谷传送门
BZOJ传送门

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:
2 2
11
00
输出样例#1:
1
输入样例#2:
5 30
12045
07105
47805
12024
12345
输出样例#2:
852

说明

【样例解释一】

0->0->1

【数据范围】

30 % 30\% 30%的数据,满足 2 ≤ N ≤ 5 2 \le N \le 5 2N5 1 ≤ T ≤ 30 1 \le T \le 30 1T30

100 % 100\% 100%的数据,满足 2 ≤ N ≤ 10 2 \le N \le 10 2N10 1 ≤ T ≤ 1000000000 1 \le T \le 1000000000 1T1000000000

解题分析

如果是 0 / 1 0/1 0/1矩阵, 直接矩阵快速幂就好了, 然而这道题有边权…

那就把每个点拆成 9 9 9个, 暴力连边跑矩乘就好了。

代码如下:

#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#define R register
#define MOD 2009
#define IN inline
#define W while
#define gc getchar()
#define MX 120
int n, bd;
long long T;
struct Matrix {int dat[MX][MX];} ans, mp;
IN Matrix operator * (const Matrix &x, const Matrix &y)
{
    Matrix ret;
    std::memset(ret.dat, 0, sizeof(ret.dat));
    for (R int i = 1; i <= bd; ++i)
    for (R int j = 1; j <= bd; ++j)
    for (R int k = 1; k <= bd; ++k)
    ret.dat[i][j] = (ret.dat[i][j] + x.dat[i][k] * y.dat[k][j] % MOD) % MOD;
    return ret;
}
IN void qpow()
{
    for (R int i = 1; i <= bd; ++i) ans.dat[i][i] = 1;
    W(T)
    {
        if(T & 1) ans = ans * mp;
        mp = mp * mp, T >>= 1;
    }
}
char buf[20];
int main(void)
{
     scanf("%d%lld", &n, &T); bd = n * 9;
     for (R int i = 1; i <= n; ++i)
     for (R int j = 1; j <= 8; ++j)
     mp.dat[(i - 1) * 9 + j][(i - 1) * 9 + j + 1] = 1;
     for (R int i = 1; i <= n; ++i)
     {
     	scanf("%s", buf + 1);
     	for (R int j = 1; j <= n; ++j)
     	{
     		if(buf[j] != '0')
     		mp.dat[(i - 1) * 9 + buf[j] - '0'][(j - 1) * 9 + 1] = 1;
     	}
     }
     qpow();
     printf("%d", ans.dat[1][n * 9 - 8]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值