1 条题解
-
0
「JOI 2014 Final」年轮蛋糕 题解
问题分析
我们有一个环形蛋糕,总共有 个切口,将蛋糕分成 块,每块大小为 。我们需要在环形蛋糕上切 刀(只能在切口位置),将蛋糕分成 块,目标是最大化最小块的大小。
这是一个典型的最大化最小值问题,可以使用二分答案来解决。
解题思路
1. 环形数组处理
由于蛋糕是环形的,我们将其复制一份接在后面,形成长度为 的数组,这样可以方便地处理环形情况。
vector<int> a(m + 1); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); a[i + n] = a[i]; // 环形复制 }2. 二分答案框架
我们二分查找可能的最小块的最大值 :
- 如果存在一种切法使得三块蛋糕的大小都 ,那么 是可行的,尝试更大的值
- 否则, 不可行,需要减小
long long l = 0, r = 1e15, ans = 0; while (l <= r) { long long mid = (l + r) >> 1; if (check(mid)) { ans = mid; l = mid + 1; } else { r = mid - 1; } }3. Check 函数的核心逻辑
check(val)函数判断是否存在一种切法,使得三块蛋糕的大小都至少为 。3.1 预处理 R 数组
对于每个起始位置 ,计算 表示从 开始,累加蛋糕块直到总和 时的下一个位置:
vector<int> R(m + 1); long long sum = 0; for (int l = 1, r = 1; l <= m; l++) { while (r <= m && sum < val) { sum += a[r]; r++; } R[l] = r; // 从l开始,到r-1结束的区间和 >= val sum -= a[l]; }3.2 检查可行性
对于每个可能的起始位置 (),我们尝试切三刀:
- 第一刀在位置 ,第二刀在 ,第三刀在
- 检查这三刀是否都在环形范围内(不超过 )
for (int i = 1; i <= n; i++) { int to = R[i]; // 第一段结束位置 if (to > i + n) continue; to = R[to]; // 第二段结束位置 if (to > i + n) continue; to = R[to]; // 第三段结束位置 if (to > i + n) continue; return true; // 找到可行解 }如果存在这样的 ,说明可以找到三刀使得每块大小都 。
算法正确性证明
1. 二分答案的正确性
设最优解为 ,那么:
- 对于所有 ,都存在切法使得最小块
- 对于所有 ,都不存在这样的切法
因此二分框架可以正确找到 。
2. Check 函数的正确性
对于固定的起始位置 :
- 保证了第一块蛋糕大小
- 保证了第二块蛋糕大小
- 保证了第三块蛋糕大小
由于环形复制,我们只需要检查 从 到 的所有可能起始位置。
复杂度分析
- 预处理前缀和:
- 二分答案: 次迭代
- 每次 Check:(预处理 R 数组)+ (检查所有起始位置)
- 总复杂度:
对于 ,这个复杂度是可以接受的。
示例验证
样例 1
输入:
6 1 5 4 5 2 4处理过程:
- 环形复制:
[1,5,4,5,2,4,1,5,4,5,2,4] - 二分查找,最终找到答案
- 验证:从位置 开始切,三刀分别在位置 ,得到的三块大小为:
- 块1:
- 块2:
- 块3: 最小块大小为
总结
本题通过以下技巧解决了环形蛋糕分割问题:
- 环形数组复制处理环形结构
- 二分答案框架解决最大化最小值问题
- 双指针预处理快速计算满足条件的区间端点
- 贪心检查验证二分答案的可行性
这种方法高效且正确,能够在规定时间内解决大规模数据。
- 1
信息
- ID
- 5350
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者