1 条题解
-
0
题目分析
我们需要构造一个二分图的完美匹配:
- 左部 :所有大小为 的 子集
- 右部 :所有大小为 的 子集
- 边关系: 时存在边
- 条件:
根据 Hall 定理,这样的完美匹配一定存在,但需要给出具体的构造方法。
关键观察
- 集合的二进制表示:每个子集用一个 位二进制数表示,低位对应小元素
- 包含关系: 当且仅当 可以通过从 中删除一个元素得到
- 平衡条件:由于 ,每个 子集的补集大小
算法思路
核心思想:括号匹配法
将集合的二进制表示看作一个括号序列:
1表示左括号(集合包含该元素)0表示右括号(集合不包含该元素)
具体步骤
对于输入的大小为 的集合 :
-
扫描二进制位(从低位到高位,即元素 0 到 n-1)
- 遇到
1(集合包含该元素):计数器sum加 1 - 遇到
0(集合不包含该元素):计数器sum减 1
- 遇到
-
记录最大前缀和位置
- 跟踪
sum的最大值mx及其位置loc
- 跟踪
-
删除最大前缀和位置的元素
- 返回 删除第
loc个元素后的集合
- 返回 删除第
代码实现
#include "hall.h" using namespace std; int solve(int n, int K, int s) { int mx = -2, loc = 0, sum = 0; for (int i = 0; i < n; i++) { if (s & (1 << i)) sum++; // 遇到1,计数器加1 else sum--; // 遇到0,计数器减1 // 记录最大前缀和的位置 if (sum > mx) { mx = sum; loc = i; } } // 删除最大前缀和位置的元素 return s ^ (1 << loc); }算法正确性证明
为什么这样构造是完美匹配?
- 单射性:不同的 -子集删除不同位置的元素得到不同的 -子集
- 满射性:每个 -子集 都能找到唯一的 -子集 使得
- 包含关系:显然
括号匹配的直观理解
- 最大前缀和位置对应一个"关键元素"
- 删除该元素能保持匹配的平衡性
- 在 的条件下,这种构造保证了一一对应
复杂度分析
- 时间复杂度: 每次查询
- 空间复杂度:
- 总复杂度:,其中 是查询次数
算法优势
- 简单高效:线性扫描即可完成
- 无需预处理:每次查询独立处理
- 保证正确性:基于组合数学的经典构造
- 适合交互:响应快速,内存占用小
该算法巧妙地利用了括号序列的性质,将复杂的组合匹配问题转化为简单的前缀和扫描,实现了优雅而高效的解决方案。
- 1
信息
- ID
- 3306
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 31
- 已通过
- 1
- 上传者