1 条题解
-
0
题解
问题分析
题目要求计算从 到 再返回 的回路数量,满足:
- 总步数恰好为
- 每个格子最多访问一次
- 必须经过所有 个景点
关键观察
-
路径结构:由于步数限制和不能重复访问,实际上路径是两条不相交的路径:
- 一条从 到
- 一条从 返回
- 这两条路径合起来覆盖所有景点
-
组合数学:在网格图中,从 到 的路径数为:
-
容斥原理:需要处理两条路径不相交的条件,使用 Lindström–Gessel–Viennot 引理
算法思路
Lindström–Gessel–Viennot 引理应用:
-
问题转化:将回路分解为两条路径:
- 路径1:
- 路径2:
- 这样确保两条路径不相交
-
状态设计:
dp[i][j][b]表示处理到第 个点,上一条路径终点在 ,奇偶性为 的方案数- 通过容斥排除相交的路径
-
转移方程:
- 延续当前路径:
dp[i+1][j][b] += dp[i][j][b] * comb(a[i], a[i+1]) - 交换路径:
dp[i+1][i][b^1] += dp[i][j][b] * comb(a[j], a[i+1]) - 容斥修正:减去相交情况的重复计数
- 延续当前路径:
核心函数
comb(a, b)计算从点 到点 的路径数:
int comb(const pii &a, const pii &b) { if(a.first > b.first || a.second > b.second) return 0; return C(b.second - a.second + b.first - a.first, b.second - a.second); }动态规划转移
dp[i+1][j][b] = (dp[i+1][j][b] + v * comb(a[i], a[i+1])) % p; dp[i+1][i][b^1] = (dp[i+1][i][b^1] + v * comb(a[j], a[i+1])) % p; dp[i+1][i+1][1] = (dp[i+1][i+1][1] - v * comb(a[i], a[i+1]) * comb(a[j], a[i+1]) % p + p) % p;算法步骤
- 预处理:计算组合数
- 输入处理:将所有景点按坐标和排序
- 第一次DP:计算包含 和 的路径方案
- 第二次DP:计算修正后的路径方案(交换起点)
- 容斥计算:用两次DP结果相减得到最终答案
- 输出:结果乘以2(两条路径对称)
复杂度分析
- 预处理:,
- 动态规划:,但 实际可接受
- 总复杂度:
算法标签
- 组合数学
- 动态规划
- 容斥原理
- Lindström–Gessel–Viennot 引理
- 不相交路径计数
- 网格图路径
- 1
信息
- ID
- 3944
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 5
- 已通过
- 1
- 上传者