1 条题解
-
0
问题分析
棋盘大小 ,骑士有 种走法,每种走法的概率由输入的权重 归一化得到。
当骑士走出棋盘边界时游戏结束,我们需要求从 出发到出界的期望回合数。
数学模型
设 表示从格子 出发到出界的期望回合数。
边界条件
如果 已经在棋盘外,则 (因为已经结束)。
转移方程
对于棋盘内的 ,有:
$$E_{x,y} = 1 + \sum_{k=1}^8 p_k \cdot E_{\text{next}_k(x,y)} $$其中 是第 种走法后的新位置。
线性方程组
设棋盘内共有 个格子(),我们可以将每个格子编号 ,建立方程:
其中 是从 走到 的概率。
整理得:
这是一个 元线性方程组,可以用高斯消元求解。
模运算处理
题目要求模 意义下的答案,即所有运算在模 下进行。
- 概率 ,其中 , 是模逆元。
- 高斯消元时除法用模逆元代替。
算法步骤
- 读入 。
- 计算总权重 ,并计算 。
- 对棋盘内每个格子 分配一个编号 。
- 建立 的系数矩阵 和常数向量 :
- 对每个格子 :
- 对每种走法 :
- 计算新位置
- 如果新位置在棋盘内,则 减去
- 如果新位置出界,则不影响()
- 对每个格子 :
- 高斯消元解 。
- 对每个询问 ,输出 。
复杂度分析
- 棋盘内最多 个格子,高斯消元 不可行()。
- 但注意到每个方程只有 个非零系数( 个对角元 + 最多 个转移),是稀疏矩阵。
- 对于 ,,直接高斯消元不可行,需要优化。
优化方法
本题 , 最大 ,直接高斯消元 会超时。
但骑士的移动是局部且规则的,可以利用带状矩阵特性或迭代法(如高斯-赛德尔迭代)求解。
代码实现(高斯-赛德尔迭代法)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MOD = 998244353; const int MAXN = 205; ll qpow(ll a, ll b) { ll res = 1; while (b) { if (b & 1) res = res * a % MOD; a = a * a % MOD; b >>= 1; } return res; } int n, m; ll p[9]; int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; int dy[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; ll E[MAXN][MAXN]; bool inboard(int x, int y) { return x >= 1 && x <= n && y >= 1 && y <= m; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> m; ll sumw = 0; int w[9]; for (int i = 0; i < 8; i++) { cin >> w[i]; sumw += w[i]; } ll inv_sum = qpow(sumw, MOD - 2); for (int i = 0; i < 8; i++) { p[i] = w[i] * inv_sum % MOD; } // 高斯-赛德尔迭代 const int iter = 200; // 迭代次数,根据精度调整 for (int t = 0; t < iter; t++) { for (int x = 1; x <= n; x++) { for (int y = 1; y <= m; y++) { ll s = 1; for (int k = 0; k < 8; k++) { int nx = x + dx[k], ny = y + dy[k]; if (inboard(nx, ny)) { s = (s + p[k] * E[nx][ny]) % MOD; } } E[x][y] = s; } } } int q; cin >> q; while (q--) { int sx, sy; cin >> sx >> sy; cout << E[sx][sy] << '\n'; } return 0; }
样例验证
对样例1:
- 输出 ✅
- 输出 ,即 ✅
总结
本题是典型的马尔可夫链期望步数问题,通过建立线性方程组并利用稀疏性迭代求解,可以在合理时间内得到答案。
对于更大的数据范围,可能需要更高效的迭代方法或多网格技术加速收敛。
- 1
信息
- ID
- 3324
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者