1 条题解
-
0
题目解析
问题重述
有 条鱼按编号从小到大排列(编号越大表示鱼越大)。每条鱼被 Alice(字符
0)或 Bob(字符1)钓到。我们需要将鱼分成 个非空连续组,第 组的每条鱼获得价值 。设 Bob 的总价值为 ,Alice 的总价值为 。要求 ,求最小的 。如果不可能,输出 。核心思想
1. 从“组边界”的角度思考
每组鱼的价值等于它前面有多少组。换句话说,每增加一个组边界,该边界之后的所有鱼的价值都会 +1。
设第 个组边界位于第 条鱼之后(即第 条鱼是前 组,第 条鱼是后面的组)。那么这个边界会让第 条及之后的所有鱼的价值都增加 。
2. 得分差的贡献
对于第 条鱼和第 条鱼之间的位置,如果这里有一个组边界,那么它会给 Bob 和 Alice 的得分差贡献:
设 表示从第 条鱼到第 条鱼中,Bob 的鱼数减去 Alice 的鱼数。更精确地:
$$s_i = \sum_{j=i}^{n} \begin{cases} +1 & \text{if fish } j \text{ is Bob's} \\ -1 & \text{if fish } j \text{ is Alice's} \end{cases} $$那么,在第 条鱼之后放置一个组边界(即第 条鱼和第 条鱼在不同组),会对最终得分差贡献 。
3. 得分差的最终表达式
设第 组从第 条鱼开始,第 组从第 条鱼开始,…,第 组从第 条鱼开始,其中 。那么 Bob 与 Alice 的得分差为:
$$B - A = \sum_{j=1}^{m} (j-1) \cdot (\text{第 } j \text{ 组中 Bob 鱼数} - \text{Alice 鱼数}) $$展开后可得:
$$B - A = 0 \cdot s_{p_1} + 1 \cdot s_{p_2} + 2 \cdot s_{p_3} + \dots + (m-1) \cdot s_{p_m} $$其中 表示从第 条鱼开始的差值累积和。这个表达式可以重写为:
为什么?因为第 组边界的贡献是 ,而最后一组之后没有边界。实际上:
- 第 组中的鱼价值为 ,贡献
- 第 组中的鱼比第 组多 分,这个 分来自第 个组边界,贡献
- 第 组中的鱼比第 组多 分,这部分贡献 ,等等。
所以最终:
4. 转化为选择问题
因此, 等于若干个 值的和,其中 是每个组边界的位置(除了第一个组没有前边界)。 是从位置 到末尾的净差值。
由于 可以为负数,而我们的目标是让 ,我们只关心正数的 (因为加入负数只会减小总和,对达到目标没有帮助)。
5. 最小化组数
组数 等于“选择的 的数量” (因为第一个组没有前边界)。为了用最少的组数达到目标,我们应该选择最大的 值。
6. 算法步骤
- 从右向左遍历,计算后缀差值 (Bob 为 ,Alice 为 )
- 收集所有 的值( 从 到 ,因为最后一个位置之后不需要边界)
- 将收集的值从大到小排序
- 依次取最大的值累加,直到总和
- 答案 = 取的数量 (如果累加和 ),否则输出
示例验证
示例 1:
- 从右向左计算 :
- (鱼4: Bob)
- (鱼3: Alice)
- (鱼2: Alice)
- (鱼1: Bob)
- 的值:
- 取 ,取了 个值
- ✅
示例 3:
- 从右向左:
- :(位置 )
- 排序:
- 取 ,取了 个值
- ✅
示例 5:
- 计算 ( 从 到 ):
- 鱼6:
0→ - 鱼5:
1→ , - 鱼4:
1→ , - 鱼3:
1→ , - 鱼2:
0→ , - 鱼1:
0→ ,
- 鱼6:
- :
- 排序:
- 取 ,再取 ,取了 个值
- ✅
C++ 代码
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { int n, k; string s; cin >> n >> k >> s; vector<int> vals; int sum = 0; // 从右向左计算后缀差值 for (int i = n - 1; i > 0; --i) { sum += (s[i] == '1' ? 1 : -1); if (sum > 0) { vals.push_back(sum); } } // 从大到小排序 sort(vals.begin(), vals.end(), greater<int>()); int ans = 1; // 至少有一组 for (int x : vals) { if (k <= 0) break; k -= x; ++ans; } cout << (k > 0 ? -1 : ans) << '\n'; } return 0; }复杂度分析
- 时间复杂度:,主要来自排序
- 空间复杂度:
- 所有测试用例 总和 ,完全可行
关键点总结
- 组边界贡献模型:每个组边界给后面所有鱼的价值 +1
- 后缀差值数组: 表示从位置 开始的净差值
- 得分差 = 所选 之和( 为组边界位置)
- 贪心选择:取最大的 以最小化组数
- 答案 = 选取数量 + 1(第一个组不需要前边界)
- 1
信息
- ID
- 7056
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者