//https://vjudge.net/contest/521403#problem/H
#include<bits/stdc++.h>
#include<unordered_map>
#include<array>
#define ll long long
#define ull unsigned long long
#define all(a) a.begin(),a.end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int inf = 2e9 + 2;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-4;
const ll mod = 2009;
const int N = 2e3 + 5;
/*
写这题需要先解决一个子问题:
给你一个 n * n 的01矩阵g,如果a[i][j]代表有一条 i 到 j 的单向边,反之则没有。这个时候我问你从
一个起点 i 点走 k 步能走到 j 点方案数有多少?
如果我有一个 n * n 的矩阵,b[i][j] 代表从 i 点走 k - 1 步能走到 j 点的方案数。你会发现我拿这个矩阵乘
上最开始代表是否有边的01矩阵得到的新矩阵中 c[i][j] 代表的就是从 i 点走到 j 点走 k 步的方案数。
为什么?
我们得到的 c[i][j] = sum(b[i][mid] * a[mid][j])。这里的乘上 a[mid][i] 就相当于在 mid 点多走一步
走到 j 点。
所以我们只要把最开始的01矩阵乘上 k 次,得到的矩阵中的 c[st][ed] 就是最终答案。
那接下来还有两个问题,一个是 k 很大怎么办 ? 矩阵快速幂。
我的边权不为 1 怎么办 ? 拆点。
a 到 b 边长为 ,相当于 a 到 c ,c 到 d,d 到 b 各有一个边长为 1 的边。这样就能写成01矩阵的形式。因为这
里的 n 很小,边长也是在 9 以内的,所以矩阵很小,算上快速幂,时间复杂度完全ok。
*/
#define int ll
int n, T;
const int K = 110;
struct Matrix {
ll a[K][K];
Matrix() {}
void clear() { memset(a, 0, sizeof a); }//变成0矩阵
void init()//初始化为单位阵
{
clear();
for (int i = 0; i < K; i++)
a[i][i] = 1;
}
Matrix operator * (const Matrix& x) const
{
Matrix res;
res.clear();
for (int i = 0; i < K; i++)
for (int j = 0; j < K; j++)
for (int k = 0; k < K; k++)
(res.a[i][j] += a[i][k] * x.a[k][j] % mod) %= mod;
return res;
}
};
Matrix qpow(Matrix base, int pow)
{
Matrix ans;
ans.init();
while (pow)
{
if (pow & 1)
ans = ans * base;
pow /= 2;
base = base * base;
}
return ans;
}
void solve()
{
cin >> n >> T;
Matrix ans;
ans.clear();
for (int i = 0; i < n; i++)
{
int st = i * 9;
for (int j = 1; j <= 8; j++)
ans.a[st + j - 1][st + j] = 1;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
char ch;
cin >> ch;
int len = ch - '0';
if (len)
ans.a[i * 9 + len - 1][j * 9] = 1;
}
}
ans = qpow(ans, T);
cout << ans.a[0][(n - 1) * 9] << '\n';
}
signed main()
{
IOS;
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
H - 迷路 (矩阵快速幂, 拆点)
于 2022-10-24 18:46:52 首次发布