1 条题解
-
0
F. Multicolored Markers 题解
一、题目回顾
有 个红色格子和 个蓝色格子,总共 个格子。要求:
- 所有格子拼成一个矩形(面积为 )。
- 至少一种颜色的格子自身也拼成一个矩形(即该颜色的所有格子形成一个子矩形)。
在所有满足条件的方案中,求该矩形的最小周长。
数据范围:。
二、问题分析
设总矩形面积为 ,边长为 (),周长为 。
不妨假设红色格子形成矩形(另一种情况是对称的,最后对 互换取最小值即可)。设红色矩形的边长为 (),则一定有:
- 红色矩形可以放入总矩形中: 且 (红色矩形可以旋转,因此也可以是 且 ,但因为我们要求 且 ,所以只需考虑 且 )
对于固定的总矩形 ,我们希望知道是否存在红色矩形的分解 满足 且 。
三、算法流程
3.1 枚举总矩形
枚举 从 到 ,当 时,取 ,得到一组总矩形分解。
3.2 判断红色矩形是否可放入
对于给定的 ,我们需要判断是否存在 使得 且 。
等价于:找到一个 使得 且 (由 推出 )。因此我们需要在 的因子中,找一个落在区间 内的因子。
实际上,因为 随 增大而减小,条件 随着 增大变得更容易满足( 变小会收紧条件?仔细看: 增大 → 减小 → 要求 更严格,所以其实更大的 对红色矩形的宽度约束更紧)。我们需要在 增长的过程中维护可行的 。
关键观察:对于固定的 ,我们只需要考虑最大的满足 的 的因子。因为当 越大, 越小,条件 越容易满足。因此检查那个最大的 即可。
3.3 双指针快速判定
预处理出 的所有因子(只存 的部分),排序为数组 。
枚举 递增,用指针 指向当前的最大因子满足 。因为 单增,指针也可以单增。
对每个合法的 ,检查 。若满足,则用周长 更新答案。
3.4 对称处理
以上假设红色形成矩形。蓝色形成矩形的情况只需交换 再跑一遍,取最小周长。
四、复杂度分析
- 预处理因子:。
- 枚举总矩形边长:。
- 双指针均摊 ,小于 。
总时间复杂度 ,在 时可轻松通过。
五、参考代码
#include <bits/stdc++.h> using namespace std; typedef long long li; const int N = 1000000; // 1e6, 足够存放 sqrt(1e14) 内的因子 int lens[N]; int k; // 假设颜色 a 形成矩形,b 为另一种颜色 li solve(li a, li b) { k = 0; // 枚举 a 的因子(只存 ≤√a 的部分) for (li i = 1; i * i <= a; ++i) if (a % i == 0) lens[k++] = i; li ans = 2 * (a + b) + 2; // 初始化为一个极大的周长 li S = a + b; int p = 0; // 枚举总矩形的一边 W for (li W = 1; W * W <= S; ++W) { if (S % W != 0) continue; li H = S / W; // 移动指针到满足 lens[p] <= W 的最大因子 while (p + 1 < k && lens[p + 1] <= W) ++p; // 检查另一边是否也放得下 if (a / lens[p] <= H) ans = min(ans, 2 * (W + H)); } return ans; } int main() { li a, b; scanf("%lld%lld", &a, &b); // 分别假设红色或蓝色形成矩形 printf("%lld\n", min(solve(a, b), solve(b, a))); return 0; }
- 1
信息
- ID
- 6760
- 时间
- 3000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者