1 条题解
-
0
问题分析
我们需要计算对于每个空地格子,当它变成障碍物后,在剩余网格中运输机投放方案的数量。这是一个网格图匹配计数问题。
问题转化
- 每个运输机投放对应一条边(连接两个相邻空地)
- 每个格子最多被一条边覆盖
- 这等价于在网格图中计算边覆盖方案数
算法思路
核心思想:状态压缩DP + 快速沃尔什变换(FWT)
使用轮廓线动态规划结合集合卷积来高效计算所有可能的障碍物情况。
主要步骤
1. 预处理合法匹配模式
void dfs(int x, int cur) { if (x == m) { stk[tp++] = cur; // 存储当前行的合法匹配模式 return; } // 水平匹配 if (x && (~cur >> (x - 1) & 1)) dfs(x + 1, cur | (1 << x) | (1 << (x - 1))); // 不匹配当前位置 dfs(x + 1, cur); }2. 自底向上的DP计算
从最后一行开始向上计算,
f[i][mask]表示从第i行开始,当前行状态为mask的方案数:for (int i = n - 1; ~i; --i) { for (int t = 0; t < tp; ++t) { // 遍历所有合法匹配模式 if (a[i] & stk[t]) continue; // 跳过与障碍物冲突的模式 int s = bm ^ (a[i] | stk[t]); // 可用的列集合 if (i + 1 < n) { // 与下一行的状态进行组合 for (int ss = s;; ss = (ss - 1) & s) { inc(f[i][ss | (bm ^ s)], f[i + 1][bm ^ ss]); if (!ss) break; } } else { f[i][bm ^ s] = 1; // 最后一行基础情况 } } if (i) FWT(f[i]); // 使用FWT加速状态转移 }3. 计算每个格子作为障碍物的影响
对于每个格子
(i,j),计算它变成障碍物后的方案数:// 初始化为总方案数 for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) ans[i][j] = sum; // 减去包含该格子的方案数 for (int i = 0; i < (1 << m); ++i) for (int t = 0; t < m; ++t) if (i >> t & 1) dec(ans[0][t], f[0][i]);4. 使用FWT进行高效卷积
void FWT(int *arr) { for (int i = 1; i < (1 << m); i <<= 1) for (int j = 0; j < (1 << m); j += (i << 1)) for (int k = j; k < (j | i); ++k) inc(arr[k | i], arr[k]); }算法原理
状态表示
f[i][mask]: 从第i行开始,当前行状态为mask的方案数mask的二进制位表示对应列是否被当前行的匹配所覆盖
状态转移
通过快速沃尔什变换(FWT)将状态转移从 优化到 :
- FWT:将状态转换到"频域",使卷积变为点乘
- 卷积计算:在频域中进行高效的状态组合
- IFWT:将结果转换回原始域
容斥原理
对于每个格子
(i,j):答案 = 总方案数 - 包含该格子的方案数复杂度分析
时间复杂度
- 预处理:(生成合法匹配模式)
- DP计算:(使用FWT优化后)
- 答案计算:
- 总复杂度:在 时可行
空间复杂度
- :存储DP数组
- :FWT相关数组
关键优化
1. FWT加速
将状态转移中的子集卷积转化为点乘,大幅降低复杂度。
2. 滚动数组
在计算过程中复用数组空间,减少内存使用。
3. 位运算优化
使用内置函数
__builtin_popcount快速计算二进制中1的个数。4. 增量计算
对于相邻的查询,复用大部分计算结果。
算法正确性
边界情况处理
- 最后一行:基础情况正确初始化
- 障碍物冲突:跳过与障碍物冲突的匹配模式
- 边界条件:正确处理网格边界
数学严谨性
- 使用模运算避免溢出
- FWT变换保证卷积计算的正确性
- 容斥原理确保计数不重不漏
总结
本题通过结合状态压缩DP和快速沃尔什变换,高效解决了网格图匹配计数问题。算法的核心优势在于:
- 理论创新:将匹配计数问题转化为集合卷积问题
- 工程优化:使用FWT大幅降低计算复杂度
- 实现精巧:通过位运算和状态压缩高效处理状态转移
- 通用性强:框架可扩展到其他网格图计数问题
该解法在理论深度和工程实现上都达到了很高水平,体现了算法竞赛中数学与计算机科学的完美结合。
- 1
信息
- ID
- 4974
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 8
- 已通过
- 1
- 上传者