1 条题解
-
0
我们需要通过最少的操作次数,在多重集合 中插入目标数字 。每次操作可以选择一个子集 ,删除 中的所有元素,然后插入 。
关键观察:要得到 ,必须有一次操作中 包含 且不包含 。
算法思路
核心思想
从高位到低位( 到 )处理,计算需要"生成"多少次数字。
变量说明
cnt
:表示当前需要生成的目标数字数量(从高位传递到低位)ans
:初始化为 ,然后减去不需要的操作
算法步骤
- 初始化
ans = 1 << n
(最大可能操作次数) - 从 到 倒序处理:
- 从
ans
中减去 - 更新
cnt += max(cnt - a[i], 0)
- 从
代码详解
void solve() { int n; std::cin >> n; std::vector<i64> a(n); for (int i = 0; i < n; i++) { std::cin >> a[i]; } i64 ans = 1ll << n; // 初始化为 2^n i64 cnt = 1; // 初始需要生成 n 这个数字 for (int i = n - 1; i >= 0; i--) { // 减去当前位可以节省的操作次数 ans -= std::min(cnt, a[i]) << i; // 更新需要生成的数量 cnt += std::max(cnt - a[i], 0ll); } std::cout << ans << "\n"; }
算法正确性证明
为什么倒序处理?
- 要生成数字 ,需要 到 都存在
- 从高到低处理可以正确传递依赖关系
状态转移理解
min(cnt, a[i])
:当前数字 能覆盖的需求数量cnt - a[i]
:当前数字 无法满足的需求数量,需要继续向前传递cnt += max(cnt - a[i], 0)
:累积需要生成的数量
复杂度分析
- 时间复杂度:,每个数字处理一次
- 空间复杂度:,存储输入数组
- 1
信息
- ID
- 3366
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者