1 条题解
-
0
题目分析
Marisa 要从起点 走到终点 ,每次走不同的路径,路径长度不超过 ,消耗体力为路径长度的平方。需要计算在所有不同路径上的体力消耗总和。
关键点:
- 统计所有长度 的不同路径
- 对每条长度为 的路径,累加
- 答案对 取模
解题思路
使用矩阵表示图的邻接关系,通过矩阵快速幂和分治策略高效计算:
- 矩阵表示:邻接矩阵 中 表示从 到 的边数
- 路径计数: 表示长度为 的路径数量
- 分治计算:使用分治法同时计算三个量:
- (路径总数)
- (路径长度和)
- (路径长度平方和)
关键公式
对于 ,有分治递推:
类似地,带权重的和式也有相应的递推关系。
完整代码
#include <bits/stdc++.h> #define ci const int #define ll long long using namespace std; ci N = 105, mod = 1e9 + 7; inline int Mod(ci x) { return x < mod ? x : (x - mod); } int n, m, q; ll k; struct mat { int v[N][N]; mat() { memset(v, 0, sizeof(v)); } inline mat operator * (const mat &x) const { mat ans; for (int k = 1; k <= n; ++k) for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) ans.v[i][j] = (ans.v[i][j] + (ll)v[i][k] * x.v[k][j]) % mod; return ans; } inline mat operator + (const mat &x) const { mat ans; for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) ans.v[i][j] = Mod(v[i][j] + x.v[i][j]); return ans; } inline mat operator * (ci &x) const { mat ans; for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) ans.v[i][j] = (ll)v[i][j] * x % mod; return ans; } } A, Al, E0, E1, E2; void Solve(ll L) { if (L == 1) { E0 = E1 = E2 = Al = A; return; } if (L & 1) { Solve(L - 1); Al = Al * A; mat e0 = E0, e1 = E1, e2 = E2; E0 = A + A * e0; E1 = A + A * (e1 + e0); E2 = A + A * (e2 + e1 * 2 + e0); } else { Solve(L >> 1); mat e0 = E0, e1 = E1, e2 = E2; ll half = L / 2; E0 = e0 + Al * e0; E1 = e1 + Al * (e1 + e0 * (half % mod)); E2 = e2 + Al * (e2 + e1 * (L % mod) + e0 * ((__int128)half * half % mod)); Al = Al * Al; } } int main() { scanf("%d%d%lld%d", &n, &m, &k, &q); for (int x, y; m; --m) { scanf("%d%d", &x, &y); ++A.v[x][y]; } Solve(k); for (int x, y; q; --q) { scanf("%d%d", &x, &y); printf("%d\n", E2.v[x][y]); } return 0; }代码说明
A:图的邻接矩阵,A.v[i][j]表示从 到 的边数Al:,长度为 的路径数量矩阵E0:,长度 的路径总数E1:,路径长度和E2:,路径长度平方和(最终答案)
Solve函数:
- 采用分治策略计算矩阵幂和相关和式
- 处理奇数情况和偶数情况的递推
- 使用
__int128处理大数乘法
复杂度分析
- 时间复杂度:
- 矩阵乘法:
- 分治深度:
- 空间复杂度:
- 1
信息
- ID
- 3682
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者